From 000878fc9fc1e52684f99a6265fac7410b6eab9c Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 15 Aug 2025 12:51:27 +0200 Subject: [PATCH 01/14] feat: compact trace --- core/engine/Cargo.toml | 1 + core/engine/src/error.rs | 49 +- .../engine/src/handler/custom_node_adapter.rs | 4 +- core/engine/src/handler/decision.rs | 24 +- core/engine/src/handler/expression/mod.rs | 38 +- core/engine/src/handler/function/function.rs | 3 +- core/engine/src/handler/function/mod.rs | 26 +- .../src/handler/function/module/console.rs | 3 +- core/engine/src/handler/function_v1/mod.rs | 3 +- core/engine/src/handler/graph.rs | 47 +- core/engine/src/handler/node.rs | 90 +++- core/engine/src/handler/table/mod.rs | 5 +- core/engine/src/handler/table/zen.rs | 16 +- core/engine/src/util/transform_attribute.rs | 8 +- core/expression/Cargo.toml | 3 + core/expression/src/functions/arguments.rs | 5 +- core/expression/src/functions/deprecated.rs | 24 +- core/expression/src/functions/internal.rs | 1 + .../src/intellisense/types/provider.rs | 1 - core/expression/src/lib.rs | 2 + core/expression/src/variable/mod.rs | 483 +---------------- core/expression/src/vm/date/mod.rs | 10 +- core/expression/src/vm/vm.rs | 1 + core/macros/Cargo.toml | 13 + core/macros/src/lib.rs | 8 + core/macros/src/to_variable.rs | 161 ++++++ core/types/Cargo.toml | 13 + core/types/src/constant.rs | 1 + core/types/src/lib.rs | 4 + core/types/src/rcvalue/conv.rs | 75 +++ core/types/src/rcvalue/de.rs | 133 +++++ core/types/src/rcvalue/mod.rs | 19 + core/types/src/rcvalue/ser.rs | 26 + .../src/variable/conv.rs | 29 - core/{expression => types}/src/variable/de.rs | 5 +- core/types/src/variable/impls.rs | 196 +++++++ core/types/src/variable/mod.rs | 495 ++++++++++++++++++ core/types/src/variable/ref_ser.rs | 207 ++++++++ .../{expression => types}/src/variable/ser.rs | 2 +- .../types => types/src/variable_type}/conv.rs | 2 +- .../types => types/src/variable_type}/mod.rs | 0 .../types => types/src/variable_type}/util.rs | 6 +- 42 files changed, 1605 insertions(+), 637 deletions(-) create mode 100644 core/macros/Cargo.toml create mode 100644 core/macros/src/lib.rs create mode 100644 core/macros/src/to_variable.rs create mode 100644 core/types/Cargo.toml create mode 100644 core/types/src/constant.rs create mode 100644 core/types/src/lib.rs create mode 100644 core/types/src/rcvalue/conv.rs create mode 100644 core/types/src/rcvalue/de.rs create mode 100644 core/types/src/rcvalue/mod.rs create mode 100644 core/types/src/rcvalue/ser.rs rename core/{expression => types}/src/variable/conv.rs (76%) rename core/{expression => types}/src/variable/de.rs (98%) create mode 100644 core/types/src/variable/impls.rs create mode 100644 core/types/src/variable/mod.rs create mode 100644 core/types/src/variable/ref_ser.rs rename core/{expression => types}/src/variable/ser.rs (96%) rename core/{expression/src/variable/types => types/src/variable_type}/conv.rs (98%) rename core/{expression/src/variable/types => types/src/variable_type}/mod.rs (100%) rename core/{expression/src/variable/types => types/src/variable_type}/util.rs (99%) diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 66bea3da..39d43c48 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -27,6 +27,7 @@ rquickjs = { version = "0.9", features = ["macro", "loader", "rust-alloc", "futu jsonschema = "0.29" zen-expression = { path = "../expression", version = "0.49.1" } zen-tmpl = { path = "../template", version = "0.49.1" } +zen-types = { path = "../types" } [dev-dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } diff --git a/core/engine/src/error.rs b/core/engine/src/error.rs index 4cd79486..f5f22673 100644 --- a/core/engine/src/error.rs +++ b/core/engine/src/error.rs @@ -1,11 +1,12 @@ use crate::handler::graph::DecisionGraphValidationError; -use crate::handler::node::NodeError; +use crate::handler::node::NodError; use crate::loader::LoaderError; use jsonschema::{ErrorIterator, ValidationError}; use serde::ser::SerializeMap; use serde::{Serialize, Serializer}; use serde_json::{Map, Value}; use std::iter::once; +use std::ops::Deref; use thiserror::Error; #[derive(Debug, Error)] @@ -14,7 +15,7 @@ pub enum EvaluationError { LoaderError(Box), #[error("Node error")] - NodeError(Box), + NodeError(Box), #[error("Depth limit exceeded")] DepthLimitExceeded, @@ -38,11 +39,35 @@ impl Serialize for EvaluationError { } EvaluationError::NodeError(err) => { map.serialize_entry("type", "NodeError")?; - map.serialize_entry("nodeId", &err.node_id)?; - map.serialize_entry("source", &err.source.to_string())?; - if let Some(trace) = &err.trace { - map.serialize_entry("trace", &trace)?; + match err.deref() { + NodError::Internal => map.serialize_entry("source", "Internal")?, + NodError::Other(o) => map.serialize_entry("source", &o.to_string())?, + NodError::Display(d) => map.serialize_entry("source", d.as_str())?, + NodError::Node { + node_id, + source, + trace, + } => { + map.serialize_entry("nodeId", node_id.as_str())?; + map.serialize_entry("source", &source.to_string())?; + + if let Some(trace) = &trace { + map.serialize_entry( + "trace", + &serde_json::to_string(&trace.serialize_ref()).unwrap(), + )?; + } + } + NodError::PartialTrace { trace, message } => { + map.serialize_entry("source", message.as_str())?; + if let Some(trace) = &trace { + map.serialize_entry( + "trace", + &serde_json::to_string(&trace.serialize_ref()).unwrap(), + )?; + } + } } } EvaluationError::LoaderError(err) => { @@ -83,15 +108,15 @@ impl From> for Box { } } -impl From for Box { - fn from(error: NodeError) -> Self { - Box::new(EvaluationError::NodeError(error.into())) +impl From for Box { + fn from(value: NodError) -> Self { + Box::new(EvaluationError::NodeError(Box::new(value))) } } -impl From> for Box { - fn from(error: Box) -> Self { - Box::new(EvaluationError::NodeError(error)) +impl From> for Box { + fn from(value: Box) -> Self { + Box::new(EvaluationError::NodeError(value)) } } diff --git a/core/engine/src/handler/custom_node_adapter.rs b/core/engine/src/handler/custom_node_adapter.rs index 17b29c78..84ae5c7f 100644 --- a/core/engine/src/handler/custom_node_adapter.rs +++ b/core/engine/src/handler/custom_node_adapter.rs @@ -1,4 +1,4 @@ -use crate::handler::node::{NodeRequest, NodeResult}; +use crate::handler::node::{NodError, NodeRequest, NodeResult}; use crate::model::{DecisionNode, DecisionNodeKind}; use anyhow::anyhow; use json_dotpath::DotPaths; @@ -18,7 +18,7 @@ pub struct NoopCustomNode; impl CustomNodeAdapter for NoopCustomNode { async fn handle(&self, _: CustomNodeRequest) -> NodeResult { - Err(anyhow!("Custom node handler not provided")) + Err(NodError::Internal) } } diff --git a/core/engine/src/handler/decision.rs b/core/engine/src/handler/decision.rs index 89415a19..252efc08 100644 --- a/core/engine/src/handler/decision.rs +++ b/core/engine/src/handler/decision.rs @@ -1,7 +1,7 @@ use crate::handler::custom_node_adapter::CustomNodeAdapter; use crate::handler::function::function::Function; use crate::handler::graph::{DecisionGraph, DecisionGraphConfig}; -use crate::handler::node::{NodeRequest, NodeResponse, NodeResult}; +use crate::handler::node::{NodError, NodeRequest, NodeResponse, NodeResult}; use crate::loader::DecisionLoader; use crate::model::DecisionNodeKind; use crate::util::validator_cache::ValidatorCache; @@ -11,6 +11,7 @@ use std::pin::Pin; use std::rc::Rc; use std::sync::Arc; use tokio::sync::Mutex; +use zen_expression::variable::ToVariable; pub struct DecisionHandler { trace: bool, @@ -54,7 +55,11 @@ impl DecisionHandle _ => Err(anyhow!("Unexpected node type")), }?; - let sub_decision = self.loader.load(&content.key).await?; + let sub_decision = self + .loader + .load(&content.key) + .await + .map_err(|_| NodError::Internal)?; let sub_tree = DecisionGraph::try_new(DecisionGraphConfig { content: sub_decision, max_depth: self.max_depth, @@ -63,7 +68,8 @@ impl DecisionHandle iteration: request.iteration + 1, trace: self.trace, validator_cache: Some(self.validator_cache.clone()), - })? + }) + .map_err(|_| NodError::Internal)? .with_function(self.js_function.clone()); let sub_tree_mutex = Arc::new(Mutex::new(sub_tree)); @@ -77,14 +83,10 @@ impl DecisionHandle let mut sub_tree_ref = sub_tree_mutex.lock().await; sub_tree_ref.reset_graph(); - sub_tree_ref - .evaluate(input) - .await - .map(|r| NodeResponse { - output: r.result, - trace_data: serde_json::to_value(r.trace).ok(), - }) - .map_err(|e| e.source) + sub_tree_ref.evaluate(input).await.map(|r| NodeResponse { + output: r.result, + trace_data: Some(r.trace.to_variable()), + }) } }) .await diff --git a/core/engine/src/handler/expression/mod.rs b/core/engine/src/handler/expression/mod.rs index 372787e8..dc08bd07 100644 --- a/core/engine/src/handler/expression/mod.rs +++ b/core/engine/src/handler/expression/mod.rs @@ -1,21 +1,23 @@ -use crate::handler::node::{NodeRequest, NodeResponse, NodeResult, PartialTraceError}; +use crate::handler::node::{NodeRequest, NodeResponse, NodeResult}; use crate::model::{DecisionNodeKind, ExpressionNodeContent}; use ahash::{HashMap, HashMapExt}; +use std::rc::Rc; use std::sync::Arc; -use anyhow::{anyhow, Context}; +use crate::handler::node::NodError; +use anyhow::anyhow; use serde::Serialize; use tokio::sync::Mutex; -use zen_expression::variable::Variable; -use zen_expression::Isolate; +use zen_expression::variable::{ToVariable, Variable}; +use zen_expression::{Isolate, ToVariable}; pub struct ExpressionHandler { trace: bool, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, ToVariable)] struct ExpressionTrace { - result: String, + result: Variable, } impl ExpressionHandler { @@ -60,7 +62,9 @@ impl<'a> ExpressionHandlerInner<'a> { async fn handle(&mut self, input: Variable, content: &'a ExpressionNodeContent) -> NodeResult { let result = Variable::empty_object(); - let mut trace_map = self.trace.then(|| HashMap::<&str, ExpressionTrace>::new()); + let mut trace_map = self + .trace + .then(|| HashMap::, ExpressionTrace>::new()); self.isolate.set_environment(input.depth_clone(1)); for expression in &content.expressions { @@ -68,21 +72,17 @@ impl<'a> ExpressionHandlerInner<'a> { continue; } - let value = self - .isolate - .run_standard(&expression.value) - .with_context(|| PartialTraceError { - trace: trace_map - .as_ref() - .map(|s| serde_json::to_value(s).ok()) - .flatten(), + let value = self.isolate.run_standard(&expression.value).map_err(|_| { + NodError::PartialTrace { + trace: trace_map.as_ref().map(|v| v.to_variable()), message: format!(r#"Failed to evaluate expression: "{}""#, &expression.value), - })?; + } + })?; if let Some(tmap) = &mut trace_map { tmap.insert( - &expression.key, + Rc::from(expression.key.as_str()), ExpressionTrace { - result: serde_json::to_string(&value).unwrap_or("Error".to_owned()), + result: value.clone(), }, ); } @@ -101,7 +101,7 @@ impl<'a> ExpressionHandlerInner<'a> { Ok(NodeResponse { output: result, - trace_data: trace_map.map(|tm| serde_json::to_value(tm).ok()).flatten(), + trace_data: trace_map.as_ref().map(|v| v.to_variable()), }) } } diff --git a/core/engine/src/handler/function/function.rs b/core/engine/src/handler/function/function.rs index 3ff83ce0..fc62256e 100644 --- a/core/engine/src/handler/function/function.rs +++ b/core/engine/src/handler/function/function.rs @@ -10,6 +10,7 @@ use rquickjs::promise::MaybePromise; use rquickjs::{async_with, AsyncContext, AsyncRuntime, CatchResultExt, Ctx, Module}; use serde::{Deserialize, Serialize}; use zen_expression::variable::Variable; +use zen_expression::ToVariable; pub struct FunctionConfig { pub(crate) listeners: Option>>, @@ -129,7 +130,7 @@ impl Function { } } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, ToVariable)] pub struct HandlerResponse { pub logs: Vec, pub data: Variable, diff --git a/core/engine/src/handler/function/mod.rs b/core/engine/src/handler/function/mod.rs index 2dfe47f3..cc599056 100644 --- a/core/engine/src/handler/function/mod.rs +++ b/core/engine/src/handler/function/mod.rs @@ -2,18 +2,18 @@ use std::rc::Rc; use std::sync::atomic::Ordering; use std::time::Duration; -use ::serde::{Deserialize, Serialize}; -use anyhow::anyhow; -use rquickjs::{async_with, CatchResultExt, Object}; -use serde_json::json; - use crate::handler::function::error::FunctionResult; use crate::handler::function::function::{Function, HandlerResponse}; use crate::handler::function::module::console::Log; use crate::handler::function::serde::JsValue; -use crate::handler::node::{NodeRequest, NodeResponse, NodeResult, PartialTraceError}; +use crate::handler::node::{NodError, NodeRequest, NodeResponse, NodeResult}; use crate::model::{DecisionNodeKind, FunctionNodeContent}; use crate::ZEN_CONFIG; +use ::serde::{Deserialize, Serialize}; +use anyhow::anyhow; +use rquickjs::{async_with, CatchResultExt, Object}; +use serde_json::json; +use zen_expression::variable::ToVariable; pub(crate) mod error; pub(crate) mod function; @@ -58,9 +58,9 @@ impl FunctionHandler { }?; let start = std::time::Instant::now(); - if content.omit_nodes { - request.input.dot_remove("$nodes"); - } + // if content.omit_nodes { + request.input.dot_remove("$nodes"); + // } let module_name = self .function @@ -93,7 +93,7 @@ impl FunctionHandler { Ok(NodeResponse { output: response.data, - trace_data: self.trace.then(|| json!({ "log": response.logs })), + trace_data: self.trace.then(|| response.logs.to_variable()), }) } Err(e) => { @@ -103,10 +103,10 @@ impl FunctionHandler { ms_since_run: start.elapsed().as_millis() as usize, }); - Err(anyhow!(PartialTraceError { + Err(NodError::PartialTrace { message: e.to_string(), - trace: Some(json!({ "log": log })), - })) + trace: Some(log.to_variable()), + }) } } } diff --git a/core/engine/src/handler/function/module/console.rs b/core/engine/src/handler/function/module/console.rs index 011314ab..0d7249a9 100644 --- a/core/engine/src/handler/function/module/console.rs +++ b/core/engine/src/handler/function/module/console.rs @@ -8,6 +8,7 @@ use crate::handler::function::listener::{RuntimeEvent, RuntimeListener}; use rquickjs::prelude::Rest; use rquickjs::{Ctx, Object, Value}; use serde::{Deserialize, Serialize}; +use zen_expression::ToVariable; pub(crate) struct ConsoleListener; @@ -28,7 +29,7 @@ impl RuntimeListener for ConsoleListener { } } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, ToVariable, Clone)] #[serde(rename_all = "camelCase")] pub struct Log { pub lines: Vec, diff --git a/core/engine/src/handler/function_v1/mod.rs b/core/engine/src/handler/function_v1/mod.rs index 1dde7059..acf53031 100644 --- a/core/engine/src/handler/function_v1/mod.rs +++ b/core/engine/src/handler/function_v1/mod.rs @@ -6,6 +6,7 @@ use crate::model::{DecisionNodeKind, FunctionNodeContent}; use anyhow::anyhow; use rquickjs::Runtime; use serde_json::json; +use zen_expression::variable::ToVariable; pub(crate) mod runtime; mod script; @@ -43,7 +44,7 @@ impl FunctionHandler { let response = result_response?; Ok(NodeResponse { output: response.output, - trace_data: self.trace.then(|| json!({ "log": response.log })), + trace_data: self.trace.then(|| response.log.to_variable()), }) } } diff --git a/core/engine/src/handler/graph.rs b/core/engine/src/handler/graph.rs index f74389dc..75f0fbb2 100644 --- a/core/engine/src/handler/graph.rs +++ b/core/engine/src/handler/graph.rs @@ -7,7 +7,7 @@ use crate::handler::function::module::zen::ZenListener; use crate::handler::function::FunctionHandler; use crate::handler::function_v1; use crate::handler::function_v1::runtime::create_runtime; -use crate::handler::node::{NodeRequest, PartialTraceError}; +use crate::handler::node::{NodError, NodeRequest, PartialTraceError}; use crate::handler::table::zen::DecisionTableHandler; use crate::handler::traversal::{GraphWalker, StableDiDecisionGraph}; use crate::loader::DecisionLoader; @@ -25,7 +25,8 @@ use std::rc::Rc; use std::sync::Arc; use std::time::Instant; use thiserror::Error; -use zen_expression::variable::Variable; +use zen_expression::variable::{ToVariable, Variable}; +use zen_expression::ToVariable; pub struct DecisionGraph { initial_graph: StableDiDecisionGraph, @@ -142,22 +143,19 @@ impl DecisionGraph< .count() } - pub async fn evaluate( - &mut self, - context: Variable, - ) -> Result { + pub async fn evaluate(&mut self, context: Variable) -> Result { let root_start = Instant::now(); self.validate().map_err(|e| NodeError { node_id: "".to_string(), - source: anyhow!(e), + source: anyhow!(e).into(), trace: None, })?; if self.iteration >= self.max_depth { - return Err(NodeError { + return Err(NodError::Node { node_id: "".to_string(), - source: anyhow!(EvaluationError::DepthLimitExceeded), + source: Box::new(NodError::Internal), trace: None, }); } @@ -218,7 +216,7 @@ impl DecisionGraph< .get_or_insert(validator_key, &json_schema) .await .map_err(|e| NodeError { - source: e.into(), + source: NodError::from(e.to_string()), node_id: node.id.clone(), trace: error_trace(&node_traces), })?; @@ -228,7 +226,8 @@ impl DecisionGraph< source: anyhow!(serde_json::to_value( Into::>::into(e) ) - .unwrap_or_default()), + .unwrap_or_default()) + .into(), node_id: node.id.clone(), trace: error_trace(&node_traces), })?; @@ -257,7 +256,7 @@ impl DecisionGraph< .get_or_insert(validator_key, &json_schema) .await .map_err(|e| NodeError { - source: e.into(), + source: NodError::from(e.to_string()), node_id: node.id.clone(), trace: error_trace(&node_traces), })?; @@ -266,10 +265,7 @@ impl DecisionGraph< validator .validate(&incoming_data_json) .map_err(|e| NodeError { - source: anyhow!(serde_json::to_value( - Into::>::into(e) - ) - .unwrap_or_default()), + source: NodError::from(e.to_string()), node_id: node.id.clone(), trace: error_trace(&node_traces), })?; @@ -308,11 +304,11 @@ impl DecisionGraph< .handle(node_request.clone()) .await .map_err(|e| { - if let Some(detailed_err) = e.downcast_ref::() { + if let NodError::PartialTrace { trace, message } = &e { trace!({ input: node_request.input.clone(), output: Variable::Null, - trace_data: detailed_err.trace.clone(), + trace_data: trace.clone(), }); } @@ -420,11 +416,11 @@ impl DecisionGraph< .handle(node_request.clone()) .await .map_err(|e| { - if let Some(detailed_err) = e.downcast_ref::() { + if let NodError::PartialTrace { trace, message } = &e { trace!({ input: node_request.input.clone(), output: Variable::Null, - trace_data: detailed_err.trace.clone(), + trace_data: trace.clone(), }); } @@ -536,7 +532,7 @@ pub struct DecisionGraphResponse { pub trace: Option>, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, ToVariable)] #[serde(rename_all = "camelCase")] pub struct DecisionGraphTrace { pub input: Variable, @@ -544,15 +540,12 @@ pub struct DecisionGraphTrace { pub name: String, pub id: String, pub performance: Option, - pub trace_data: Option, + pub trace_data: Option, pub order: u32, } -pub(crate) fn error_trace(trace: &Option>) -> Option { - trace - .as_ref() - .map(|s| serde_json::to_value(s).ok()) - .flatten() +pub(crate) fn error_trace(trace: &Option>) -> Option { + trace.as_ref().map(|s| s.to_variable()) } fn create_validator_cache_key(content: &Value) -> u64 { diff --git a/core/engine/src/handler/node.rs b/core/engine/src/handler/node.rs index ebc5438c..2a0f722e 100644 --- a/core/engine/src/handler/node.rs +++ b/core/engine/src/handler/node.rs @@ -1,16 +1,14 @@ use crate::model::DecisionNode; use serde::{Deserialize, Serialize}; -use serde_json::Value; use std::fmt::{Display, Formatter}; use std::sync::Arc; -use thiserror::Error; use zen_expression::variable::Variable; #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct NodeResponse { pub output: Variable, - pub trace_data: Option, + pub trace_data: Option, } #[derive(Debug, Serialize, Clone)] @@ -20,12 +18,11 @@ pub struct NodeRequest { pub node: Arc, } -#[derive(Error, Debug)] +#[derive(Debug)] pub struct NodeError { pub node_id: String, - pub trace: Option, - #[source] - pub source: anyhow::Error, + pub trace: Option, + pub source: NodError, } impl Display for NodeError { @@ -36,7 +33,7 @@ impl Display for NodeError { #[derive(Debug)] pub(crate) struct PartialTraceError { - pub trace: Option, + pub trace: Option, pub message: String, } @@ -46,4 +43,79 @@ impl Display for PartialTraceError { } } -pub type NodeResult = anyhow::Result; +pub type NodeResult = Result; + +#[derive(Debug)] +pub enum NodError { + Internal, + Other(Box), + Display(String), // For non-Error types that implement Display + Node { + node_id: String, + trace: Option, + source: Box, + }, + PartialTrace { + trace: Option, + message: String, + }, +} + +impl NodError { + /// Convert any error type to NodError + pub fn from_error(error: E) -> Self { + Self::Other(Box::new(error)) + } + + /// Add context to this error + pub fn context(self, context: C) -> Self { + Self::Display(format!("{}: {}", context, self)) + } + + /// Add context to this error using a closure + pub fn with_context C>(self, f: F) -> Self { + Self::Display(format!("{}: {}", f(), self)) + } +} + +impl Display for NodError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + NodError::Internal => write!(f, "Internal error occurred"), + NodError::Other(err) => write!(f, "{}", err), + NodError::Display(msg) => write!(f, "{}", msg), + NodError::Node { source, .. } => { + write!(f, "{}", source) + } + NodError::PartialTrace { trace, message } => { + if let Some(var) = trace { + write!(f, "{} (trace: {:?})", message, var) + } else { + write!(f, "{}", message) + } + } + } + } +} + +impl From for NodError { + fn from(value: anyhow::Error) -> Self { + Self::Other(value.into()) + } +} + +impl From for NodError { + fn from(value: String) -> Self { + Self::Display(value) + } +} + +impl From for NodError { + fn from(value: NodeError) -> Self { + Self::Node { + source: Box::new(value.source), + trace: value.trace.clone(), + node_id: value.node_id, + } + } +} diff --git a/core/engine/src/handler/table/mod.rs b/core/engine/src/handler/table/mod.rs index 58f00118..b4ed3b3c 100644 --- a/core/engine/src/handler/table/mod.rs +++ b/core/engine/src/handler/table/mod.rs @@ -1,13 +1,14 @@ pub mod zen; use zen_expression::variable::Variable; +use zen_expression::ToVariable; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, ToVariable)] pub(crate) enum RowOutputKind { Variable(Variable), } -#[derive(Debug, Default)] +#[derive(Debug, Default, ToVariable)] pub(crate) struct RowOutput { output: OutputMap, } diff --git a/core/engine/src/handler/table/zen.rs b/core/engine/src/handler/table/zen.rs index 079682ff..0938fae3 100644 --- a/core/engine/src/handler/table/zen.rs +++ b/core/engine/src/handler/table/zen.rs @@ -7,10 +7,10 @@ use crate::handler::table::{RowOutput, RowOutputKind}; use crate::model::{DecisionNodeKind, DecisionTableContent, DecisionTableHitPolicy}; use serde::Serialize; use tokio::sync::Mutex; -use zen_expression::variable::Variable; -use zen_expression::Isolate; +use zen_expression::variable::{ToVariable, Variable}; +use zen_expression::{Isolate, ToVariable}; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, ToVariable)] struct RowResult { rule: Option>, reference_map: Option>, @@ -89,10 +89,7 @@ impl<'a> DecisionTableHandlerInner<'a> { if let Some(result) = self.evaluate_row(&content, i) { return Ok(NodeResponse { output: result.output.to_json().await, - trace_data: self - .trace - .then(|| serde_json::to_value(&result).ok()) - .flatten(), + trace_data: self.trace.then(|| result.to_variable()), }); } } @@ -118,10 +115,7 @@ impl<'a> DecisionTableHandlerInner<'a> { Ok(NodeResponse { output: Variable::from_array(outputs), - trace_data: self - .trace - .then(|| serde_json::to_value(&results).ok()) - .flatten(), + trace_data: self.trace.then(|| results.to_variable()), }) } diff --git a/core/engine/src/util/transform_attribute.rs b/core/engine/src/util/transform_attribute.rs index b68bed1c..213cad12 100644 --- a/core/engine/src/util/transform_attribute.rs +++ b/core/engine/src/util/transform_attribute.rs @@ -16,7 +16,9 @@ impl TransformAttributes { Some(input_field) => { let mut isolate = Isolate::new(); isolate.set_environment(node_input.clone()); - let calculated_input = isolate.run_standard(input_field.as_str())?; + let calculated_input = isolate + .run_standard(input_field.as_str()) + .context("Failed to run standard")?; let nodes = node_input.dot("$nodes").unwrap_or(Variable::Null); match &calculated_input { @@ -42,7 +44,7 @@ impl TransformAttributes { } }; - let mut trace_data: Option = None; + let mut trace_data: Option = None; let mut output = match self.execution_mode { TransformExecutionMode::Single => { let response = evaluate(input).await?; @@ -73,7 +75,7 @@ impl TransformAttributes { output_array.push(response.output); } - trace_data.replace(Value::Array(trace_datum)); + trace_data.replace(Variable::from_array(trace_datum)); Variable::from_array(output_array) } }; diff --git a/core/expression/Cargo.toml b/core/expression/Cargo.toml index cd0c4fdc..edbbbcde 100644 --- a/core/expression/Cargo.toml +++ b/core/expression/Cargo.toml @@ -30,6 +30,9 @@ nohash-hasher = "0.2.0" strsim = "0.11" iana-time-zone = "0.1" +zen-macros = { path = "../macros" } +zen-types = { path = "../types" } + [dev-dependencies] criterion = { workspace = true } csv = "1" diff --git a/core/expression/src/functions/arguments.rs b/core/expression/src/functions/arguments.rs index 17b0b335..b3ff781e 100644 --- a/core/expression/src/functions/arguments.rs +++ b/core/expression/src/functions/arguments.rs @@ -1,13 +1,16 @@ -use crate::variable::{DynamicVariable, RcCell}; +use crate::variable::DynamicVariable; use crate::Variable; use ahash::HashMap; use anyhow::Context; use rust_decimal::Decimal; +use std::cell::RefCell; use std::ops::Deref; use std::rc::Rc; pub struct Arguments<'a>(pub &'a [Variable]); +type RcCell = Rc>; + impl<'a> Deref for Arguments<'a> { type Target = [Variable]; diff --git a/core/expression/src/functions/deprecated.rs b/core/expression/src/functions/deprecated.rs index f344c60a..12eef7a4 100644 --- a/core/expression/src/functions/deprecated.rs +++ b/core/expression/src/functions/deprecated.rs @@ -117,11 +117,29 @@ impl From<&DeprecatedFunction> for Rc { mod imp { use super::*; use crate::vm::helpers::DateUnit; + use crate::vm::VMError; + use zen_types::variable::Variable; fn __internal_convert_datetime(timestamp: &V) -> anyhow::Result { - timestamp - .try_into() - .context("Failed to convert value to date time") + match timestamp { + Variable::String(a) => date_time(a), + #[allow(deprecated)] + Variable::Number(a) => NaiveDateTime::from_timestamp_opt( + a.to_i64().ok_or_else(|| VMError::OpcodeErr { + opcode: "DateManipulation".into(), + message: "Failed to extract date".into(), + })?, + 0, + ) + .ok_or_else(|| VMError::ParseDateTimeErr { + timestamp: a.to_string(), + }), + _ => Err(VMError::OpcodeErr { + opcode: "DateManipulation".into(), + message: "Unsupported type".into(), + }), + } + .context("Failed to convert value to date time") } pub fn parse_date(args: Arguments) -> anyhow::Result { diff --git a/core/expression/src/functions/internal.rs b/core/expression/src/functions/internal.rs index 0e467ad2..7b0c1719 100644 --- a/core/expression/src/functions/internal.rs +++ b/core/expression/src/functions/internal.rs @@ -304,6 +304,7 @@ impl From<&InternalFunction> for Rc { pub(crate) mod imp { use crate::functions::arguments::Arguments; + use crate::vm::date::DynamicVariableExt; use crate::vm::VmDate; use crate::{Variable as V, Variable}; use anyhow::{anyhow, Context}; diff --git a/core/expression/src/intellisense/types/provider.rs b/core/expression/src/intellisense/types/provider.rs index bcea1f4e..1c8c6a0e 100644 --- a/core/expression/src/intellisense/types/provider.rs +++ b/core/expression/src/intellisense/types/provider.rs @@ -151,7 +151,6 @@ impl TypesProvider { .root_data .dot_insert_detached(key_type.as_ref(), value_type.kind.shallow_clone()) { - println!("NewVar: {new_var:?}"); scope.root_data = new_var; }; diff --git a/core/expression/src/lib.rs b/core/expression/src/lib.rs index 7f54d584..1d5760e0 100644 --- a/core/expression/src/lib.rs +++ b/core/expression/src/lib.rs @@ -69,6 +69,8 @@ pub mod validate; pub mod variable; pub mod vm; +pub use zen_macros::ToVariable; + pub use exports::{ compile_expression, compile_unary_expression, evaluate_expression, evaluate_unary_expression, }; diff --git a/core/expression/src/variable/mod.rs b/core/expression/src/variable/mod.rs index e2410ef4..b22b4cf4 100644 --- a/core/expression/src/variable/mod.rs +++ b/core/expression/src/variable/mod.rs @@ -1,481 +1,4 @@ -use ahash::HashMap; -use rust_decimal::prelude::Zero; -use rust_decimal::Decimal; -use serde_json::Value; -use std::any::Any; -use std::cell::RefCell; -use std::collections::hash_map::Entry; -use std::fmt::{Debug, Display, Formatter}; -use std::ops::Deref; -use std::rc::Rc; +use std::fmt::{Debug, Display}; -mod conv; -mod de; -mod ser; -mod types; - -pub use de::VariableDeserializer; -pub use types::VariableType; - -pub(crate) type RcCell = Rc>; - -pub enum Variable { - Null, - Bool(bool), - Number(Decimal), - String(Rc), - Array(RcCell>), - Object(RcCell, Variable>>), - Dynamic(Rc), -} - -pub trait DynamicVariable: Display { - fn type_name(&self) -> &'static str; - - fn as_any(&self) -> &dyn Any; - - fn to_value(&self) -> Value; -} - -impl Variable { - pub fn from_array(arr: Vec) -> Self { - Self::Array(Rc::new(RefCell::new(arr))) - } - - pub fn from_object(obj: HashMap, Self>) -> Self { - Self::Object(Rc::new(RefCell::new(obj))) - } - - pub fn empty_object() -> Self { - Variable::Object(Default::default()) - } - - pub fn empty_array() -> Self { - Variable::Array(Default::default()) - } - - pub fn as_str(&self) -> Option<&str> { - match self { - Variable::String(s) => Some(s.as_ref()), - _ => None, - } - } - - pub fn as_rc_str(&self) -> Option> { - match self { - Variable::String(s) => Some(s.clone()), - _ => None, - } - } - - pub fn as_array(&self) -> Option>> { - match self { - Variable::Array(arr) => Some(arr.clone()), - _ => None, - } - } - - pub fn is_array(&self) -> bool { - match self { - Variable::Array(_) => true, - _ => false, - } - } - - pub fn as_object(&self) -> Option, Variable>>> { - match self { - Variable::Object(obj) => Some(obj.clone()), - _ => None, - } - } - - pub fn is_object(&self) -> bool { - match self { - Variable::Object(_) => true, - _ => false, - } - } - - pub fn as_bool(&self) -> Option { - match self { - Variable::Bool(b) => Some(*b), - _ => None, - } - } - - pub fn as_number(&self) -> Option { - match self { - Variable::Number(n) => Some(*n), - _ => None, - } - } - - pub fn type_name(&self) -> &'static str { - match self { - Variable::Null => "null", - Variable::Bool(_) => "bool", - Variable::Number(_) => "number", - Variable::String(_) => "string", - Variable::Array(_) => "array", - Variable::Object(_) => "object", - Variable::Dynamic(d) => d.type_name(), - } - } - - pub fn dynamic(&self) -> Option<&T> { - match self { - Variable::Dynamic(d) => d.as_any().downcast_ref::(), - _ => None, - } - } - - pub fn to_value(&self) -> Value { - Value::from(self.shallow_clone()) - } - - pub fn dot(&self, key: &str) -> Option { - key.split('.') - .try_fold(self.shallow_clone(), |var, part| match var { - Variable::Object(obj) => { - let reference = obj.borrow(); - reference.get(part).map(|v| v.shallow_clone()) - } - _ => None, - }) - } - - fn dot_head(&self, key: &str) -> Option { - let mut parts = Vec::from_iter(key.split('.')); - parts.pop(); - - parts - .iter() - .try_fold(self.shallow_clone(), |var, part| match var { - Variable::Object(obj) => { - let mut obj_ref = obj.borrow_mut(); - Some(match obj_ref.entry(Rc::from(*part)) { - Entry::Occupied(occ) => occ.get().shallow_clone(), - Entry::Vacant(vac) => vac.insert(Self::empty_object()).shallow_clone(), - }) - } - _ => None, - }) - } - - fn dot_head_detach(&self, key: &str) -> (Variable, Option) { - let mut parts = Vec::from_iter(key.split('.')); - parts.pop(); - - let cloned_self = self.depth_clone(1); - let head = parts - .iter() - .try_fold(cloned_self.shallow_clone(), |var, part| match var { - Variable::Object(obj) => { - let mut obj_ref = obj.borrow_mut(); - Some(match obj_ref.entry(Rc::from(*part)) { - Entry::Occupied(mut occ) => { - let var = occ.get(); - let new_obj = match var { - Variable::Object(_) => var.depth_clone(1), - _ => Variable::empty_object(), - }; - - occ.insert(new_obj.shallow_clone()); - new_obj - } - Entry::Vacant(vac) => vac.insert(Self::empty_object()).shallow_clone(), - }) - } - _ => None, - }); - - (cloned_self, head) - } - - pub fn dot_remove(&self, key: &str) -> Option { - let last_part = key.split('.').last()?; - let head = self.dot_head(key)?; - let Variable::Object(object_ref) = head else { - return None; - }; - - let mut object = object_ref.borrow_mut(); - object.remove(last_part) - } - - pub fn dot_insert(&self, key: &str, variable: Variable) -> Option { - let last_part = key.split('.').last()?; - let head = self.dot_head(key)?; - let Variable::Object(object_ref) = head else { - return None; - }; - - let mut object = object_ref.borrow_mut(); - object.insert(Rc::from(last_part), variable) - } - - pub fn dot_insert_detached(&self, key: &str, variable: Variable) -> Option { - let last_part = key.split('.').last()?; - let (new_var, head_opt) = self.dot_head_detach(key); - let head = head_opt?; - let Variable::Object(object_ref) = head else { - return None; - }; - - let mut object = object_ref.borrow_mut(); - object.insert(Rc::from(last_part), variable); - Some(new_var) - } - - pub fn merge(&mut self, patch: &Variable) -> Variable { - let _ = merge_variables(self, patch, true, MergeStrategy::InPlace); - - self.shallow_clone() - } - - pub fn merge_clone(&mut self, patch: &Variable) -> Variable { - let mut new_self = self.shallow_clone(); - - let _ = merge_variables(&mut new_self, patch, true, MergeStrategy::CloneOnWrite); - new_self - } - - pub fn shallow_clone(&self) -> Self { - match self { - Variable::Null => Variable::Null, - Variable::Bool(b) => Variable::Bool(*b), - Variable::Number(n) => Variable::Number(*n), - Variable::String(s) => Variable::String(s.clone()), - Variable::Array(a) => Variable::Array(a.clone()), - Variable::Object(o) => Variable::Object(o.clone()), - Variable::Dynamic(d) => Variable::Dynamic(d.clone()), - } - } - - pub fn deep_clone(&self) -> Self { - match self { - Variable::Array(a) => { - let arr = a.borrow(); - Variable::from_array(arr.iter().map(|v| v.deep_clone()).collect()) - } - Variable::Object(o) => { - let obj = o.borrow(); - Variable::from_object( - obj.iter() - .map(|(k, v)| (k.clone(), v.deep_clone())) - .collect(), - ) - } - _ => self.shallow_clone(), - } - } - - pub fn depth_clone(&self, depth: usize) -> Self { - match depth.is_zero() { - true => self.shallow_clone(), - false => match self { - Variable::Array(a) => { - let arr = a.borrow(); - Variable::from_array(arr.iter().map(|v| v.depth_clone(depth - 1)).collect()) - } - Variable::Object(o) => { - let obj = o.borrow(); - Variable::from_object( - obj.iter() - .map(|(k, v)| (k.clone(), v.depth_clone(depth - 1))) - .collect(), - ) - } - _ => self.shallow_clone(), - }, - } - } -} - -impl Clone for Variable { - fn clone(&self) -> Self { - self.shallow_clone() - } -} - -#[derive(Copy, Clone)] -enum MergeStrategy { - InPlace, - CloneOnWrite, -} - -fn merge_variables( - doc: &mut Variable, - patch: &Variable, - top_level: bool, - strategy: MergeStrategy, -) -> bool { - if patch.is_array() && top_level { - *doc = patch.shallow_clone(); - return true; - } - - if !patch.is_object() && top_level { - return false; - } - - if doc.is_object() && patch.is_object() { - let doc_ref = doc.as_object().unwrap(); - let patch_ref = patch.as_object().unwrap(); - if Rc::ptr_eq(&doc_ref, &patch_ref) { - return false; - } - - let patch = patch_ref.borrow(); - match strategy { - MergeStrategy::InPlace => { - let mut map = doc_ref.borrow_mut(); - for (key, value) in patch.deref() { - if value == &Variable::Null { - map.remove(key); - } else { - let entry = map.entry(key.clone()).or_insert(Variable::Null); - merge_variables(entry, value, false, strategy); - } - } - - return true; - } - MergeStrategy::CloneOnWrite => { - let mut changed = false; - let mut new_map = None; - - for (key, value) in patch.deref() { - // Get or create the new map if we haven't yet - let map = if let Some(ref mut m) = new_map { - m - } else { - let m = doc_ref.borrow().clone(); - new_map = Some(m); - new_map.as_mut().unwrap() - }; - - if value == &Variable::Null { - // Remove null values - if map.remove(key).is_some() { - changed = true; - } - } else { - // Handle nested merging - let entry = map.entry(key.clone()).or_insert(Variable::Null); - if merge_variables(entry, value, false, strategy) { - changed = true; - } - } - } - - // Only update doc if changes were made - if changed { - if let Some(new_map) = new_map { - *doc = Variable::Object(Rc::new(RefCell::new(new_map))); - } - return true; - } - - return false; - } - } - } else { - let new_value = patch.shallow_clone(); - if *doc != new_value { - *doc = new_value; - return true; - } - - return false; - } -} - -impl Display for Variable { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Variable::Null => write!(f, "null"), - Variable::Bool(b) => match *b { - true => write!(f, "true"), - false => write!(f, "false"), - }, - Variable::Number(n) => write!(f, "{n}"), - Variable::String(s) => write!(f, "\"{s}\""), - Variable::Array(arr) => { - let arr = arr.borrow(); - let s = arr - .iter() - .map(|v| v.to_string()) - .collect::>() - .join(","); - write!(f, "[{s}]") - } - Variable::Object(obj) => { - let obj = obj.borrow(); - let s = obj - .iter() - .map(|(k, v)| format!("\"{k}\":{v}")) - .collect::>() - .join(","); - - write!(f, "{{{s}}}") - } - Variable::Dynamic(d) => write!(f, "{d}"), - } - } -} - -impl Debug for Variable { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self) - } -} - -impl PartialEq for Variable { - fn eq(&self, other: &Self) -> bool { - match (&self, &other) { - (Variable::Null, Variable::Null) => true, - (Variable::Bool(b1), Variable::Bool(b2)) => b1 == b2, - (Variable::Number(n1), Variable::Number(n2)) => n1 == n2, - (Variable::String(s1), Variable::String(s2)) => s1 == s2, - (Variable::Array(a1), Variable::Array(a2)) => a1 == a2, - (Variable::Object(obj1), Variable::Object(obj2)) => obj1 == obj2, - (Variable::Dynamic(d1), Variable::Dynamic(d2)) => Rc::ptr_eq(d1, d2), - _ => false, - } - } -} - -impl Eq for Variable {} - -#[cfg(test)] -mod tests { - use crate::Variable; - use rust_decimal_macros::dec; - use serde_json::json; - - #[test] - fn insert_detached() { - let some_data: Variable = json!({ "customer": { "firstName": "John" }}).into(); - - let a_a = some_data - .dot_insert_detached("a.a", Variable::Number(dec!(1))) - .unwrap(); - let a_b = a_a - .dot_insert_detached("a.b", Variable::Number(dec!(2))) - .unwrap(); - let a_c = a_b - .dot_insert_detached("a.c", Variable::Number(dec!(3))) - .unwrap(); - - assert_eq!(a_a.dot("a"), Some(Variable::from(json!({ "a": 1 })))); - assert_eq!( - a_b.dot("a"), - Some(Variable::from(json!({ "a": 1, "b": 2 }))) - ); - assert_eq!( - a_c.dot("a"), - Some(Variable::from(json!({ "a": 1, "b": 2, "c": 3 }))) - ); - } -} +pub use zen_types::variable::{DynamicVariable, ToVariable, Variable, VariableDeserializer}; +pub use zen_types::variable_type::VariableType; diff --git a/core/expression/src/vm/date/mod.rs b/core/expression/src/vm/date/mod.rs index 99355b75..ed02ea78 100644 --- a/core/expression/src/vm/date/mod.rs +++ b/core/expression/src/vm/date/mod.rs @@ -175,7 +175,7 @@ impl VmDate { } mod helper { - use crate::vm::date::{Duration, DurationUnit}; + use crate::vm::date::{Duration, DurationUnit, DynamicVariableExt}; use crate::Variable; use chrono::{ DateTime, Datelike, Days, LocalResult, Month, Months, NaiveDate, NaiveDateTime, Offset, @@ -475,8 +475,12 @@ mod helper { } } -impl dyn DynamicVariable { - pub(crate) fn as_date(&self) -> Option<&VmDate> { +pub(crate) trait DynamicVariableExt { + fn as_date(&self) -> Option<&VmDate>; +} + +impl DynamicVariableExt for dyn DynamicVariable { + fn as_date(&self) -> Option<&VmDate> { self.as_any().downcast_ref::() } } diff --git a/core/expression/src/vm/vm.rs b/core/expression/src/vm/vm.rs index 79a50f16..01e2b1e3 100644 --- a/core/expression/src/vm/vm.rs +++ b/core/expression/src/vm/vm.rs @@ -4,6 +4,7 @@ use crate::functions::registry::FunctionRegistry; use crate::functions::{internal, MethodRegistry}; use crate::variable::Variable; use crate::variable::Variable::*; +use crate::vm::date::DynamicVariableExt; use crate::vm::error::VMError::*; use crate::vm::error::VMResult; use crate::vm::interval::{VmInterval, VmIntervalData}; diff --git a/core/macros/Cargo.toml b/core/macros/Cargo.toml new file mode 100644 index 00000000..78d892e3 --- /dev/null +++ b/core/macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "zen-macros" +version = "0.49.1" +edition = "2024" +publish = false + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1" +quote = "1" +syn = { version = "2", features = ["full"] } diff --git a/core/macros/src/lib.rs b/core/macros/src/lib.rs new file mode 100644 index 00000000..dffbbd3c --- /dev/null +++ b/core/macros/src/lib.rs @@ -0,0 +1,8 @@ +use proc_macro::TokenStream; + +mod to_variable; + +#[proc_macro_derive(ToVariable)] +pub fn derive_to_variable(input: TokenStream) -> TokenStream { + to_variable::to_variable_impl(input) +} diff --git a/core/macros/src/to_variable.rs b/core/macros/src/to_variable.rs new file mode 100644 index 00000000..e92a8ae9 --- /dev/null +++ b/core/macros/src/to_variable.rs @@ -0,0 +1,161 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{Data, DeriveInput, Fields, Variant, parse_macro_input}; + +pub fn to_variable_impl(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = &input.ident; + + match &input.data { + Data::Struct(data_struct) => generate_struct_impl(name, data_struct), + Data::Enum(data_enum) => generate_enum_impl(name, data_enum), + _ => syn::Error::new_spanned(&input, "ToVariable only supports structs and enums") + .to_compile_error() + .into(), + } +} + +fn generate_struct_impl(name: &syn::Ident, data_struct: &syn::DataStruct) -> TokenStream { + let fields = match &data_struct.fields { + Fields::Named(fields_named) => &fields_named.named, + _ => { + return syn::Error::new_spanned( + name, + "ToVariable only supports structs with named fields", + ) + .to_compile_error() + .into(); + } + }; + + let field_count = fields.len(); + let field_mappings = fields.iter().map(|field| { + let field_name = field.ident.as_ref().unwrap(); + let field_name_str = field_name.to_string(); + + quote! { + map.insert( + std::rc::Rc::from(#field_name_str), + (&self.#field_name).to_variable() + ); + } + }); + + let expanded = quote! { + impl zen_expression::variable::ToVariable for #name { + fn to_variable(&self) -> zen_expression::Variable { + use ahash::{HashMap, HashMapExt}; + use std::rc::Rc; + + let mut map = HashMap::with_capacity(#field_count); + #(#field_mappings)* + zen_expression::Variable::from_object(map) + } + } + }; + + TokenStream::from(expanded) +} + +fn generate_enum_impl(name: &syn::Ident, data_enum: &syn::DataEnum) -> TokenStream { + let variants = data_enum + .variants + .iter() + .map(|variant| generate_variant_match(name, variant)); + + let expanded = quote! { + impl zen_expression::variable::ToVariable for #name { + fn to_variable(&self) -> zen_expression::Variable { + use ahash::{HashMap, HashMapExt}; + use std::rc::Rc; + use zen_expression::Variable; + use zen_expression::variable::{ToVariable}; + + match self { + #(#variants)* + } + } + } + }; + + TokenStream::from(expanded) +} + +fn generate_variant_match(enum_name: &syn::Ident, variant: &Variant) -> proc_macro2::TokenStream { + let variant_name = &variant.ident; + let variant_str = variant_name.to_string(); + + match &variant.fields { + // Unit variant: MyEnum::Variant + Fields::Unit => { + quote! { + #enum_name::#variant_name => Variable::String(Rc::from(#variant_str)), + } + } + + // Tuple variant: MyEnum::Variant(T1, T2, ...) + Fields::Unnamed(fields) => { + let field_count = fields.unnamed.len(); + let field_patterns: Vec<_> = (0..field_count) + .map(|i| quote::format_ident!("field_{}", i)) + .collect(); + + if field_count == 1 { + // Single field - flatten directly with type + quote! { + #enum_name::#variant_name(#(#field_patterns),*) => { + let mut map = HashMap::with_capacity(2); + map.insert(Rc::from("type"), Variable::String(Rc::from(#variant_str))); + map.insert(Rc::from("value"), (#(#field_patterns)*).to_variable()); + Variable::from_object(map) + }, + } + } else { + // Multiple fields - flatten as indexed fields + let field_mappings = field_patterns.iter().enumerate().map(|(i, pattern)| { + let field_name = format!("field_{}", i); + quote! { + map.insert(Rc::from(#field_name), (#pattern).to_variable()); + } + }); + + let total_capacity = field_count + 1; // +1 for "type" + + quote! { + #enum_name::#variant_name(#(#field_patterns),*) => { + let mut map = HashMap::with_capacity(#total_capacity); + map.insert(Rc::from("type"), Variable::String(Rc::from(#variant_str))); + #(#field_mappings)* + Variable::from_object(map) + }, + } + } + } + + Fields::Named(fields) => { + let field_count = fields.named.len() + 1; // +1 for the "type" field + let field_mappings = fields.named.iter().map(|field| { + let field_name = field.ident.as_ref().unwrap(); + let field_name_str = field_name.to_string(); + + quote! { + map.insert(Rc::from(#field_name_str), (#field_name).to_variable()); + } + }); + + let field_patterns = fields.named.iter().map(|field| { + let field_name = field.ident.as_ref().unwrap(); + quote! { #field_name } + }); + + quote! { + #enum_name::#variant_name { #(#field_patterns),* } => { + let mut map = HashMap::with_capacity(#field_count); + map.insert(Rc::from("type"), Variable::String(Rc::from(#variant_str))); + #(#field_mappings)* + Variable::from_object(map) + }, + } + } + } +} diff --git a/core/types/Cargo.toml b/core/types/Cargo.toml new file mode 100644 index 00000000..a15a6131 --- /dev/null +++ b/core/types/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "zen-types" +version = "0.49.1" +edition = "2024" +publish = false + +[dependencies] +ahash = { workspace = true } +serde = { workspace = true, features = ["rc", "derive"] } +serde_json = { workspace = true, features = ["arbitrary_precision"] } +rust_decimal = { workspace = true, features = ["maths-nopanic"] } +rust_decimal_macros = { workspace = true } +nohash-hasher = "0.2.0" diff --git a/core/types/src/constant.rs b/core/types/src/constant.rs new file mode 100644 index 00000000..d4ba663d --- /dev/null +++ b/core/types/src/constant.rs @@ -0,0 +1 @@ +pub(crate) const NUMBER_TOKEN: &str = "$serde_json::private::Number"; diff --git a/core/types/src/lib.rs b/core/types/src/lib.rs new file mode 100644 index 00000000..1772aca9 --- /dev/null +++ b/core/types/src/lib.rs @@ -0,0 +1,4 @@ +mod constant; +pub mod rcvalue; +pub mod variable; +pub mod variable_type; diff --git a/core/types/src/rcvalue/conv.rs b/core/types/src/rcvalue/conv.rs new file mode 100644 index 00000000..1cf1a758 --- /dev/null +++ b/core/types/src/rcvalue/conv.rs @@ -0,0 +1,75 @@ +use crate::rcvalue::RcValue; +use crate::variable::{ToVariable, Variable}; +use rust_decimal::Decimal; +use serde_json::Value; +use std::rc::Rc; + +impl ToVariable for RcValue { + fn to_variable(&self) -> Variable { + match self { + RcValue::Null => Variable::Null, + RcValue::Bool(b) => Variable::Bool(*b), + RcValue::Number(n) => Variable::Number(*n), + RcValue::String(s) => Variable::String(Rc::from(s.as_ref())), + RcValue::Array(arr) => { + Variable::from_array(arr.iter().map(|v| v.to_variable()).collect()) + } + RcValue::Object(obj) => Variable::from_object( + obj.iter() + .map(|(k, v)| (Rc::from(k.as_ref()), v.to_variable())) + .collect(), + ), + } + } +} + +impl From<&Variable> for RcValue { + fn from(value: &Variable) -> Self { + match value { + Variable::Null => RcValue::Null, + Variable::Bool(b) => RcValue::Bool(*b), + Variable::Number(n) => RcValue::Number(*n), + Variable::String(s) => RcValue::String(s.clone()), + Variable::Array(arr) => { + let arr = arr.borrow(); + RcValue::Array(arr.iter().map(RcValue::from).collect()) + } + Variable::Object(obj) => { + let obj = obj.borrow(); + RcValue::Object( + obj.iter() + .map(|(k, v)| (k.clone(), RcValue::from(v))) + .collect(), + ) + } + Variable::Dynamic(d) => RcValue::from(&d.to_value()), + } + } +} + +impl From for RcValue { + fn from(value: Variable) -> Self { + Self::from(&value) + } +} + +impl From<&Value> for RcValue { + fn from(value: &Value) -> Self { + match value { + Value::Null => RcValue::Null, + Value::Bool(b) => RcValue::Bool(*b), + Value::Number(n) => RcValue::Number( + Decimal::from_str_exact(n.as_str()) + .or_else(|_| Decimal::from_scientific(n.as_str())) + .expect("Allowed number"), + ), + Value::String(s) => RcValue::String(Rc::from(s.as_str())), + Value::Array(arr) => RcValue::Array(arr.iter().map(RcValue::from).collect()), + Value::Object(obj) => RcValue::Object( + obj.iter() + .map(|(k, v)| (Rc::from(k.as_str()), RcValue::from(v))) + .collect(), + ), + } + } +} diff --git a/core/types/src/rcvalue/de.rs b/core/types/src/rcvalue/de.rs new file mode 100644 index 00000000..087ef1b7 --- /dev/null +++ b/core/types/src/rcvalue/de.rs @@ -0,0 +1,133 @@ +use crate::constant::NUMBER_TOKEN; +use crate::rcvalue::RcValue; +use ahash::{HashMap, HashMapExt}; +use rust_decimal::Decimal; +use rust_decimal::prelude::FromPrimitive; +use serde::de::{DeserializeSeed, Error, MapAccess, SeqAccess, Unexpected, Visitor}; +use serde::{Deserialize, Deserializer}; +use std::fmt::Formatter; +use std::marker::PhantomData; +use std::ops::Deref; +use std::rc::Rc; + +struct RcValueVisitor; + +impl<'de> Visitor<'de> for RcValueVisitor { + type Value = RcValue; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("A valid type") + } + + fn visit_bool(self, v: bool) -> Result + where + E: Error, + { + Ok(RcValue::Bool(v)) + } + + fn visit_i64(self, v: i64) -> Result + where + E: Error, + { + Ok(RcValue::Number(Decimal::from_i64(v).ok_or_else(|| { + Error::invalid_value(Unexpected::Signed(v), &self) + })?)) + } + + fn visit_u64(self, v: u64) -> Result + where + E: Error, + { + Ok(RcValue::Number(Decimal::from_u64(v).ok_or_else(|| { + Error::invalid_value(Unexpected::Unsigned(v), &self) + })?)) + } + + fn visit_f64(self, v: f64) -> Result + where + E: Error, + { + Ok(RcValue::Number(Decimal::from_f64(v).ok_or_else(|| { + Error::invalid_value(Unexpected::Float(v), &self) + })?)) + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(RcValue::String(Rc::from(v))) + } + + fn visit_unit(self) -> Result + where + E: Error, + { + Ok(RcValue::Null) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or_default()); + while let Some(value) = seq.next_element_seed(RcValueDeserializer)? { + vec.push(value); + } + + Ok(RcValue::Array(vec)) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut m = HashMap::with_capacity(map.size_hint().unwrap_or_default()); + let mut first = true; + + while let Some((key, value)) = + map.next_entry_seed(PhantomData::>, RcValueDeserializer)? + { + if first && key.deref() == NUMBER_TOKEN { + let str = match &value { + RcValue::String(s) => s.as_ref(), + _ => return Err(Error::custom("failed to deserialize number")), + }; + + return Ok(RcValue::Number( + Decimal::from_str_exact(str) + .or_else(|_| Decimal::from_scientific(str)) + .map_err(|_| Error::custom("invalid number"))?, + )); + } + + m.insert(key, value); + first = false; + } + + Ok(RcValue::Object(m)) + } +} + +pub struct RcValueDeserializer; + +impl<'de> DeserializeSeed<'de> for RcValueDeserializer { + type Value = RcValue; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(RcValueVisitor) + } +} + +impl<'de> Deserialize<'de> for RcValue { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(RcValueVisitor) + } +} diff --git a/core/types/src/rcvalue/mod.rs b/core/types/src/rcvalue/mod.rs new file mode 100644 index 00000000..3e7dd912 --- /dev/null +++ b/core/types/src/rcvalue/mod.rs @@ -0,0 +1,19 @@ +mod conv; +mod de; +mod ser; + +use ahash::HashMap; +pub use de::RcValueDeserializer; +use rust_decimal::Decimal; +use std::rc::Rc; + +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub enum RcValue { + #[default] + Null, + Bool(bool), + Number(Decimal), + String(Rc), + Array(Vec), + Object(HashMap, RcValue>), +} diff --git a/core/types/src/rcvalue/ser.rs b/core/types/src/rcvalue/ser.rs new file mode 100644 index 00000000..0cd6ca5a --- /dev/null +++ b/core/types/src/rcvalue/ser.rs @@ -0,0 +1,26 @@ +use crate::constant::NUMBER_TOKEN; +use crate::rcvalue::RcValue; +use serde::ser::SerializeStruct; +use serde::{Serialize, Serializer}; + +impl Serialize for RcValue { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + RcValue::Null => serializer.serialize_unit(), + RcValue::Bool(v) => serializer.serialize_bool(*v), + RcValue::Number(v) => { + let str = v.normalize().to_string(); + + let mut s = serializer.serialize_struct(NUMBER_TOKEN, 1)?; + s.serialize_field(NUMBER_TOKEN, &str)?; + s.end() + } + RcValue::String(v) => serializer.serialize_str(v), + RcValue::Array(v) => serializer.collect_seq(v.iter()), + RcValue::Object(v) => serializer.collect_map(v.iter()), + } + } +} diff --git a/core/expression/src/variable/conv.rs b/core/types/src/variable/conv.rs similarity index 76% rename from core/expression/src/variable/conv.rs rename to core/types/src/variable/conv.rs index 8caeb15b..b81137d1 100644 --- a/core/expression/src/variable/conv.rs +++ b/core/types/src/variable/conv.rs @@ -1,8 +1,4 @@ use crate::variable::Variable; -use crate::vm::helpers::date_time; -use crate::vm::VMError; -use chrono::NaiveDateTime; -use rust_decimal::prelude::ToPrimitive; use rust_decimal::Decimal; use serde_json::{Number, Value}; use std::rc::Rc; @@ -88,28 +84,3 @@ impl From for Value { } } } - -impl TryFrom<&Variable> for NaiveDateTime { - type Error = VMError; - - fn try_from(value: &Variable) -> Result { - match value { - Variable::String(a) => date_time(a), - #[allow(deprecated)] - Variable::Number(a) => NaiveDateTime::from_timestamp_opt( - a.to_i64().ok_or_else(|| VMError::OpcodeErr { - opcode: "DateManipulation".into(), - message: "Failed to extract date".into(), - })?, - 0, - ) - .ok_or_else(|| VMError::ParseDateTimeErr { - timestamp: a.to_string(), - }), - _ => Err(VMError::OpcodeErr { - opcode: "DateManipulation".into(), - message: "Unsupported type".into(), - }), - } - } -} diff --git a/core/expression/src/variable/de.rs b/core/types/src/variable/de.rs similarity index 98% rename from core/expression/src/variable/de.rs rename to core/types/src/variable/de.rs index 81066f37..6c3ad6fd 100644 --- a/core/expression/src/variable/de.rs +++ b/core/types/src/variable/de.rs @@ -1,7 +1,8 @@ +use crate::constant::NUMBER_TOKEN; use crate::variable::Variable; use ahash::{HashMap, HashMapExt}; -use rust_decimal::prelude::FromPrimitive; use rust_decimal::Decimal; +use rust_decimal::prelude::FromPrimitive; use serde::de::{DeserializeSeed, Error, MapAccess, SeqAccess, Unexpected, Visitor}; use serde::{Deserialize, Deserializer}; use std::fmt::Formatter; @@ -11,8 +12,6 @@ use std::rc::Rc; struct VariableVisitor; -pub(super) const NUMBER_TOKEN: &str = "$serde_json::private::Number"; - impl<'de> Visitor<'de> for VariableVisitor { type Value = Variable; diff --git a/core/types/src/variable/impls.rs b/core/types/src/variable/impls.rs new file mode 100644 index 00000000..3b6508b3 --- /dev/null +++ b/core/types/src/variable/impls.rs @@ -0,0 +1,196 @@ +use crate::variable::Variable; +use rust_decimal::Decimal; +use rust_decimal::prelude::FromPrimitive; +use serde_json::Value; +use std::collections::HashMap; +use std::rc::Rc; +use std::sync::Arc; + +pub trait ToVariable { + fn to_variable(&self) -> Variable; +} + +impl ToVariable for String { + fn to_variable(&self) -> Variable { + Variable::String(Rc::from(self.as_str())) + } +} + +impl ToVariable for str { + fn to_variable(&self) -> Variable { + Variable::String(Rc::from(self)) + } +} + +impl ToVariable for bool { + fn to_variable(&self) -> Variable { + Variable::Bool(*self) + } +} + +impl ToVariable for Decimal { + fn to_variable(&self) -> Variable { + Variable::Number(*self) + } +} + +impl ToVariable for Variable { + fn to_variable(&self) -> Variable { + self.clone() + } +} + +impl ToVariable for Value { + fn to_variable(&self) -> Variable { + Variable::from(self) + } +} + +macro_rules! impl_to_variable_numeric { + ($($t:ty),* $(,)?) => { + $( + impl ToVariable for $t { + fn to_variable(&self) -> Variable { + Variable::Number(Decimal::from(*self)) + } + } + )* + }; +} + +impl_to_variable_numeric!( + i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize +); + +impl ToVariable for f32 { + fn to_variable(&self) -> Variable { + Variable::Number(Decimal::from_f32(*self).unwrap_or_default()) + } +} + +impl ToVariable for f64 { + fn to_variable(&self) -> Variable { + Variable::Number(Decimal::from_f64(*self).unwrap_or_default()) + } +} + +impl ToVariable for Vec +where + T: ToVariable, +{ + fn to_variable(&self) -> Variable { + Variable::from_array(self.iter().map(|v| v.to_variable()).collect()) + } +} + +impl ToVariable for HashMap, V, S> +where + V: ToVariable, + S: std::hash::BuildHasher, +{ + fn to_variable(&self) -> Variable { + Variable::from_object( + self.iter() + .map(|(k, v)| (k.clone(), v.to_variable())) + .collect(), + ) + } +} + +impl ToVariable for HashMap +where + V: ToVariable, + S: std::hash::BuildHasher, +{ + fn to_variable(&self) -> Variable { + Variable::from_object( + self.iter() + .map(|(k, v)| (Rc::from(k.as_str()), v.to_variable())) + .collect(), + ) + } +} + +macro_rules! tuple_impls { + ( $( ($($T:ident),+) ),+ ) => { + $( + impl<$($T),+> ToVariable for ($($T,)+) + where + $($T: ToVariable,)+ + { + #[allow(non_snake_case)] + fn to_variable(&self) -> Variable { + let ($($T,)+) = self; + Variable::from_array(vec![ + $($T.to_variable(),)+ + ]) + } + } + )+ + }; +} + +tuple_impls! { + (T1), + (T1, T2), + (T1, T2, T3), + (T1, T2, T3, T4), + (T1, T2, T3, T4, T5) +} + +impl ToVariable for &T +where + T: ?Sized + ToVariable, +{ + fn to_variable(&self) -> Variable { + (**self).to_variable() + } +} + +impl ToVariable for &mut T +where + T: ?Sized + ToVariable, +{ + fn to_variable(&self) -> Variable { + (**self).to_variable() + } +} + +impl ToVariable for Option +where + T: ToVariable, +{ + fn to_variable(&self) -> Variable { + match self { + Some(value) => value.to_variable(), + None => Variable::Null, + } + } +} + +impl ToVariable for Box +where + T: ?Sized + ToVariable, +{ + fn to_variable(&self) -> Variable { + (**self).to_variable() + } +} + +impl ToVariable for Rc +where + T: ?Sized + ToVariable, +{ + fn to_variable(&self) -> Variable { + (**self).to_variable() + } +} + +impl ToVariable for Arc +where + T: ?Sized + ToVariable, +{ + fn to_variable(&self) -> Variable { + (**self).to_variable() + } +} diff --git a/core/types/src/variable/mod.rs b/core/types/src/variable/mod.rs new file mode 100644 index 00000000..7fca38d2 --- /dev/null +++ b/core/types/src/variable/mod.rs @@ -0,0 +1,495 @@ +use crate::variable::ref_ser::RefSerializer; +use ahash::HashMap; +use rust_decimal::Decimal; +use rust_decimal::prelude::Zero; +use serde_json::Value; +use std::any::Any; +use std::cell::RefCell; +use std::collections::hash_map::Entry; +use std::fmt::{Debug, Display, Formatter}; +use std::ops::Deref; +use std::rc::Rc; + +use crate::rcvalue::RcValue; +pub use de::VariableDeserializer; +pub use impls::ToVariable; + +mod conv; +mod de; +mod impls; +mod ref_ser; +mod ser; + +pub(crate) type RcCell = Rc>; + +pub enum Variable { + Null, + Bool(bool), + Number(Decimal), + String(Rc), + Array(RcCell>), + Object(RcCell, Variable>>), + Dynamic(Rc), +} + +pub trait DynamicVariable: Display { + fn type_name(&self) -> &'static str; + + fn as_any(&self) -> &dyn Any; + + fn to_value(&self) -> Value; +} + +impl Variable { + pub fn from_array(arr: Vec) -> Self { + Self::Array(Rc::new(RefCell::new(arr))) + } + + pub fn serialize_ref(&self) -> RcValue { + RefSerializer::new().serialize(self).unwrap() + // self.to_value() + } + + pub fn from_object(obj: HashMap, Self>) -> Self { + Self::Object(Rc::new(RefCell::new(obj))) + } + + pub fn empty_object() -> Self { + Variable::Object(Default::default()) + } + + pub fn empty_array() -> Self { + Variable::Array(Default::default()) + } + + pub fn as_str(&self) -> Option<&str> { + match self { + Variable::String(s) => Some(s.as_ref()), + _ => None, + } + } + + pub fn as_rc_str(&self) -> Option> { + match self { + Variable::String(s) => Some(s.clone()), + _ => None, + } + } + + pub fn as_array(&self) -> Option>> { + match self { + Variable::Array(arr) => Some(arr.clone()), + _ => None, + } + } + + pub fn is_array(&self) -> bool { + match self { + Variable::Array(_) => true, + _ => false, + } + } + + pub fn as_object(&self) -> Option, Variable>>> { + match self { + Variable::Object(obj) => Some(obj.clone()), + _ => None, + } + } + + pub fn is_object(&self) -> bool { + match self { + Variable::Object(_) => true, + _ => false, + } + } + + pub fn as_bool(&self) -> Option { + match self { + Variable::Bool(b) => Some(*b), + _ => None, + } + } + + pub fn as_number(&self) -> Option { + match self { + Variable::Number(n) => Some(*n), + _ => None, + } + } + + pub fn type_name(&self) -> &'static str { + match self { + Variable::Null => "null", + Variable::Bool(_) => "bool", + Variable::Number(_) => "number", + Variable::String(_) => "string", + Variable::Array(_) => "array", + Variable::Object(_) => "object", + Variable::Dynamic(d) => d.type_name(), + } + } + + pub fn dynamic(&self) -> Option<&T> { + match self { + Variable::Dynamic(d) => d.as_any().downcast_ref::(), + _ => None, + } + } + + pub fn to_value(&self) -> Value { + Value::from(self.shallow_clone()) + } + + pub fn dot(&self, key: &str) -> Option { + key.split('.') + .try_fold(self.shallow_clone(), |var, part| match var { + Variable::Object(obj) => { + let reference = obj.borrow(); + reference.get(part).map(|v| v.shallow_clone()) + } + _ => None, + }) + } + + fn dot_head(&self, key: &str) -> Option { + let mut parts = Vec::from_iter(key.split('.')); + parts.pop(); + + parts + .iter() + .try_fold(self.shallow_clone(), |var, part| match var { + Variable::Object(obj) => { + let mut obj_ref = obj.borrow_mut(); + Some(match obj_ref.entry(Rc::from(*part)) { + Entry::Occupied(occ) => occ.get().shallow_clone(), + Entry::Vacant(vac) => vac.insert(Self::empty_object()).shallow_clone(), + }) + } + _ => None, + }) + } + + fn dot_head_detach(&self, key: &str) -> (Variable, Option) { + let mut parts = Vec::from_iter(key.split('.')); + parts.pop(); + + let cloned_self = self.depth_clone(1); + let head = parts + .iter() + .try_fold(cloned_self.shallow_clone(), |var, part| match var { + Variable::Object(obj) => { + let mut obj_ref = obj.borrow_mut(); + Some(match obj_ref.entry(Rc::from(*part)) { + Entry::Occupied(mut occ) => { + let var = occ.get(); + let new_obj = match var { + Variable::Object(_) => var.depth_clone(1), + _ => Variable::empty_object(), + }; + + occ.insert(new_obj.shallow_clone()); + new_obj + } + Entry::Vacant(vac) => vac.insert(Self::empty_object()).shallow_clone(), + }) + } + _ => None, + }); + + (cloned_self, head) + } + + pub fn dot_remove(&self, key: &str) -> Option { + let last_part = key.split('.').last()?; + let head = self.dot_head(key)?; + let Variable::Object(object_ref) = head else { + return None; + }; + + let mut object = object_ref.borrow_mut(); + object.remove(last_part) + } + + pub fn dot_insert(&self, key: &str, variable: Variable) -> Option { + let last_part = key.split('.').last()?; + let head = self.dot_head(key)?; + let Variable::Object(object_ref) = head else { + return None; + }; + + let mut object = object_ref.borrow_mut(); + object.insert(Rc::from(last_part), variable) + } + + pub fn dot_insert_detached(&self, key: &str, variable: Variable) -> Option { + let last_part = key.split('.').last()?; + let (new_var, head_opt) = self.dot_head_detach(key); + let head = head_opt?; + let Variable::Object(object_ref) = head else { + return None; + }; + + let mut object = object_ref.borrow_mut(); + object.insert(Rc::from(last_part), variable); + Some(new_var) + } + + pub fn merge(&mut self, patch: &Variable) -> Variable { + let _ = merge_variables(self, patch, true, MergeStrategy::InPlace); + + self.shallow_clone() + } + + pub fn merge_clone(&mut self, patch: &Variable) -> Variable { + let mut new_self = self.shallow_clone(); + + let _ = merge_variables(&mut new_self, patch, true, MergeStrategy::CloneOnWrite); + new_self + } + + pub fn shallow_clone(&self) -> Self { + match self { + Variable::Null => Variable::Null, + Variable::Bool(b) => Variable::Bool(*b), + Variable::Number(n) => Variable::Number(*n), + Variable::String(s) => Variable::String(s.clone()), + Variable::Array(a) => Variable::Array(a.clone()), + Variable::Object(o) => Variable::Object(o.clone()), + Variable::Dynamic(d) => Variable::Dynamic(d.clone()), + } + } + + pub fn deep_clone(&self) -> Self { + match self { + Variable::Array(a) => { + let arr = a.borrow(); + Variable::from_array(arr.iter().map(|v| v.deep_clone()).collect()) + } + Variable::Object(o) => { + let obj = o.borrow(); + Variable::from_object( + obj.iter() + .map(|(k, v)| (k.clone(), v.deep_clone())) + .collect(), + ) + } + _ => self.shallow_clone(), + } + } + + pub fn depth_clone(&self, depth: usize) -> Self { + match depth.is_zero() { + true => self.shallow_clone(), + false => match self { + Variable::Array(a) => { + let arr = a.borrow(); + Variable::from_array(arr.iter().map(|v| v.depth_clone(depth - 1)).collect()) + } + Variable::Object(o) => { + let obj = o.borrow(); + Variable::from_object( + obj.iter() + .map(|(k, v)| (k.clone(), v.depth_clone(depth - 1))) + .collect(), + ) + } + _ => self.shallow_clone(), + }, + } + } +} + +impl Clone for Variable { + fn clone(&self) -> Self { + self.shallow_clone() + } +} + +#[derive(Copy, Clone)] +enum MergeStrategy { + InPlace, + CloneOnWrite, +} + +fn merge_variables( + doc: &mut Variable, + patch: &Variable, + top_level: bool, + strategy: MergeStrategy, +) -> bool { + if patch.is_array() && top_level { + *doc = patch.shallow_clone(); + return true; + } + + if !patch.is_object() && top_level { + return false; + } + + if doc.is_object() && patch.is_object() { + let doc_ref = doc.as_object().unwrap(); + let patch_ref = patch.as_object().unwrap(); + if Rc::ptr_eq(&doc_ref, &patch_ref) { + return false; + } + + let patch = patch_ref.borrow(); + match strategy { + MergeStrategy::InPlace => { + let mut map = doc_ref.borrow_mut(); + for (key, value) in patch.deref() { + if value == &Variable::Null { + map.remove(key); + } else { + let entry = map.entry(key.clone()).or_insert(Variable::Null); + merge_variables(entry, value, false, strategy); + } + } + + return true; + } + MergeStrategy::CloneOnWrite => { + let mut changed = false; + let mut new_map = None; + + for (key, value) in patch.deref() { + // Get or create the new map if we haven't yet + let map = if let Some(ref mut m) = new_map { + m + } else { + let m = doc_ref.borrow().clone(); + new_map = Some(m); + new_map.as_mut().unwrap() + }; + + if value == &Variable::Null { + // Remove null values + if map.remove(key).is_some() { + changed = true; + } + } else { + // Handle nested merging + let entry = map.entry(key.clone()).or_insert(Variable::Null); + if merge_variables(entry, value, false, strategy) { + changed = true; + } + } + } + + // Only update doc if changes were made + if changed { + if let Some(new_map) = new_map { + *doc = Variable::Object(Rc::new(RefCell::new(new_map))); + } + return true; + } + + return false; + } + } + } else { + let new_value = patch.shallow_clone(); + if *doc != new_value { + *doc = new_value; + return true; + } + + return false; + } +} + +impl Default for Variable { + fn default() -> Self { + Variable::Null + } +} + +impl Display for Variable { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Variable::Null => write!(f, "null"), + Variable::Bool(b) => match *b { + true => write!(f, "true"), + false => write!(f, "false"), + }, + Variable::Number(n) => write!(f, "{n}"), + Variable::String(s) => write!(f, "\"{s}\""), + Variable::Array(arr) => { + let arr = arr.borrow(); + let s = arr + .iter() + .map(|v| v.to_string()) + .collect::>() + .join(","); + write!(f, "[{s}]") + } + Variable::Object(obj) => { + let obj = obj.borrow(); + let s = obj + .iter() + .map(|(k, v)| format!("\"{k}\":{v}")) + .collect::>() + .join(","); + + write!(f, "{{{s}}}") + } + Variable::Dynamic(d) => write!(f, "{d}"), + } + } +} + +impl Debug for Variable { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self) + } +} + +impl PartialEq for Variable { + fn eq(&self, other: &Self) -> bool { + match (&self, &other) { + (Variable::Null, Variable::Null) => true, + (Variable::Bool(b1), Variable::Bool(b2)) => b1 == b2, + (Variable::Number(n1), Variable::Number(n2)) => n1 == n2, + (Variable::String(s1), Variable::String(s2)) => s1 == s2, + (Variable::Array(a1), Variable::Array(a2)) => a1 == a2, + (Variable::Object(obj1), Variable::Object(obj2)) => obj1 == obj2, + (Variable::Dynamic(d1), Variable::Dynamic(d2)) => Rc::ptr_eq(d1, d2), + _ => false, + } + } +} + +impl Eq for Variable {} + +#[cfg(test)] +mod tests { + use crate::variable::Variable; + use rust_decimal_macros::dec; + use serde_json::json; + + #[test] + fn insert_detached() { + let some_data: Variable = json!({ "customer": { "firstName": "John" }}).into(); + + let a_a = some_data + .dot_insert_detached("a.a", Variable::Number(dec!(1))) + .unwrap(); + let a_b = a_a + .dot_insert_detached("a.b", Variable::Number(dec!(2))) + .unwrap(); + let a_c = a_b + .dot_insert_detached("a.c", Variable::Number(dec!(3))) + .unwrap(); + + assert_eq!(a_a.dot("a"), Some(Variable::from(json!({ "a": 1 })))); + assert_eq!( + a_b.dot("a"), + Some(Variable::from(json!({ "a": 1, "b": 2 }))) + ); + assert_eq!( + a_c.dot("a"), + Some(Variable::from(json!({ "a": 1, "b": 2, "c": 3 }))) + ); + } +} diff --git a/core/types/src/variable/ref_ser.rs b/core/types/src/variable/ref_ser.rs new file mode 100644 index 00000000..f261c5e0 --- /dev/null +++ b/core/types/src/variable/ref_ser.rs @@ -0,0 +1,207 @@ +use crate::rcvalue::RcValue; +use crate::variable::Variable; +use ahash::AHashMap; +use nohash_hasher::BuildNoHashHasher; +use std::collections::HashMap; +use std::rc::Rc; + +pub struct RefSerializer { + ref_counts: HashMap>, + refs: HashMap), BuildNoHashHasher>, + string_intern: AHashMap, Rc>, + ref_data: Vec, + min_ref_count: usize, + min_str_len: usize, +} + +impl RefSerializer { + pub fn new() -> Self { + Self { + ref_counts: HashMap::default(), + refs: HashMap::default(), + string_intern: AHashMap::default(), + ref_data: Vec::new(), + min_ref_count: 2, + min_str_len: 5, + } + } + + fn escape_at_string(s: &Rc) -> Rc { + if s.starts_with('@') { + let string = format!("@{s}"); + Rc::from(string.as_str()) + } else { + s.clone() + } + } + + fn intern_string_addr(&mut self, s: &Rc) -> usize { + let reference = match self.string_intern.get(s) { + Some(interned) => interned, + None => { + self.string_intern.insert(s.clone(), s.clone()); + s + } + }; + + Rc::as_ptr(&reference) as *const () as usize + } + + pub fn serialize(mut self, var: &Variable) -> serde_json::Result { + self.count_refs(var); + self.assign_ref_ids(); + + let data = self.serialize_with_refs(var)?; + + let mut result = HashMap::default(); + if !self.ref_data.is_empty() { + result.insert(Rc::from("$refs"), RcValue::Array(self.ref_data)); + } + + result.insert(Rc::from("$root"), data); + Ok(RcValue::Object(result)) + } + + fn count_refs(&mut self, var: &Variable) { + match var { + Variable::String(s) => { + if s.len() < self.min_str_len { + return; + } + + let addr = self.intern_string_addr(s); + *self.ref_counts.entry(addr).or_insert(0) += 1; + } + Variable::Array(arr) => { + let addr = Rc::as_ptr(arr) as *const () as usize; + *self.ref_counts.entry(addr).or_insert(0) += 1; + + let borrowed = arr.borrow(); + for item in borrowed.iter() { + self.count_refs(item); + } + } + Variable::Object(obj) => { + let addr = Rc::as_ptr(obj) as *const () as usize; + *self.ref_counts.entry(addr).or_insert(0) += 1; + + let borrowed = obj.borrow(); + for (key, value) in borrowed.iter() { + let key_addr = self.intern_string_addr(key); + *self.ref_counts.entry(key_addr).or_insert(0) += 1; + self.count_refs(value); + } + } + Variable::Dynamic(_) => {} + _ => {} // Null, Bool, Number don't need ref counting + } + } + + fn assign_ref_ids(&mut self) { + let mut sorted_refs: Vec<_> = self + .ref_counts + .iter() + .filter(|&(_, &count)| count >= self.min_ref_count) + .collect(); + + sorted_refs.sort_by(|a, b| b.1.cmp(&a.1).then(b.0.cmp(&a.0))); + + self.refs.reserve(sorted_refs.len()); + self.ref_data.reserve(sorted_refs.len()); + + for (&addr, _) in sorted_refs { + let id = self.ref_data.len(); + let id_string = format!("@{id}"); + + self.refs.insert(addr, (id, Rc::from(id_string.as_str()))); + self.ref_data.push(RcValue::Null); + } + } + + fn serialize_with_refs(&mut self, var: &Variable) -> serde_json::Result { + match var { + Variable::String(s) => { + let addr = self.intern_string_addr(s); + let Some((id, id_str)) = self.refs.get(&addr) else { + return Ok(RcValue::String(Self::escape_at_string(s))); + }; + + if self.ref_data[*id] == RcValue::Null { + self.ref_data[*id] = RcValue::String(Self::escape_at_string(s)); + } + + Ok(RcValue::String(id_str.clone())) + } + + Variable::Array(arr) => { + let addr = Rc::as_ptr(arr) as *const () as usize; + let data = { + let borrowed = arr.borrow(); + let items: Result, _> = borrowed + .iter() + .map(|item| self.serialize_with_refs(item)) + .collect(); + + RcValue::Array(items?) + }; + + let Some((id, id_str)) = self.refs.get(&addr) else { + return Ok(data); + }; + + if self.ref_data[*id] == RcValue::Null { + self.ref_data[*id] = data; + } + + Ok(RcValue::String(id_str.clone())) + } + + Variable::Object(obj) => { + let addr = Rc::as_ptr(obj) as *const () as usize; + let data = { + let borrowed = obj.borrow(); + let mut map = HashMap::with_capacity_and_hasher( + borrowed.len(), + ahash::RandomState::new(), + ); + + for (key, value) in borrowed.iter() { + let key_addr = self.intern_string_addr(key); + let key_str = if let Some((key_id, key_id_str)) = self.refs.get(&key_addr) { + if self.ref_data[*key_id] == RcValue::Null { + self.ref_data[*key_id] = + RcValue::String(Self::escape_at_string(key)); + } + + key_id_str.clone() + } else { + Self::escape_at_string(key) + }; + + map.insert(key_str, self.serialize_with_refs(value)?); + } + + RcValue::Object(map) + }; + + let Some((id, id_str)) = self.refs.get(&addr) else { + return Ok(data); + }; + + if self.ref_data[*id] == RcValue::Null { + self.ref_data[*id] = data; + } + + Ok(RcValue::String(id_str.clone())) + } + + _ => Ok(RcValue::from(var)), + } + } +} + +impl Default for RefSerializer { + fn default() -> Self { + Self::new() + } +} diff --git a/core/expression/src/variable/ser.rs b/core/types/src/variable/ser.rs similarity index 96% rename from core/expression/src/variable/ser.rs rename to core/types/src/variable/ser.rs index 6bbf1d2f..1f57b709 100644 --- a/core/expression/src/variable/ser.rs +++ b/core/types/src/variable/ser.rs @@ -1,4 +1,4 @@ -use crate::variable::de::NUMBER_TOKEN; +use crate::constant::NUMBER_TOKEN; use crate::variable::Variable; use serde::ser::SerializeStruct; use serde::{Serialize, Serializer}; diff --git a/core/expression/src/variable/types/conv.rs b/core/types/src/variable_type/conv.rs similarity index 98% rename from core/expression/src/variable/types/conv.rs rename to core/types/src/variable_type/conv.rs index 761d6a1f..67be7e3f 100644 --- a/core/expression/src/variable/types/conv.rs +++ b/core/types/src/variable_type/conv.rs @@ -1,4 +1,4 @@ -use crate::variable::types::VariableType; +use crate::variable_type::VariableType; use serde_json::Value; use std::borrow::Cow; use std::cell::RefCell; diff --git a/core/expression/src/variable/types/mod.rs b/core/types/src/variable_type/mod.rs similarity index 100% rename from core/expression/src/variable/types/mod.rs rename to core/types/src/variable_type/mod.rs diff --git a/core/expression/src/variable/types/util.rs b/core/types/src/variable_type/util.rs similarity index 99% rename from core/expression/src/variable/types/util.rs rename to core/types/src/variable_type/util.rs index 031f4857..3909edb1 100644 --- a/core/expression/src/variable/types/util.rs +++ b/core/types/src/variable_type/util.rs @@ -1,8 +1,8 @@ -use crate::variable::types::VariableType; +use crate::variable_type::VariableType; use rust_decimal::prelude::Zero; use std::cell::RefCell; -use std::collections::hash_map::Entry; use std::collections::HashMap; +use std::collections::hash_map::Entry; use std::rc::Rc; impl VariableType { @@ -323,7 +323,7 @@ impl VariableType { #[cfg(test)] mod tests { - use crate::variable::VariableType; + use crate::variable_type::VariableType; use std::rc::Rc; #[test] From 67dec938fb3a60f66e19889f7e0bdf56a9fb1378 Mon Sep 17 00:00:00 2001 From: Stefan Date: Sat, 16 Aug 2025 09:55:56 +0200 Subject: [PATCH 02/14] align with changes --- bindings/c/src/custom_node.rs | 4 +- bindings/c/src/languages/go.rs | 4 +- bindings/c/src/languages/native.rs | 2 +- bindings/c/src/result.rs | 6 +- bindings/nodejs/src/custom_node.rs | 8 +- bindings/nodejs/src/decision.rs | 8 +- bindings/nodejs/src/engine.rs | 8 +- bindings/nodejs/src/types.rs | 2 +- bindings/uniffi/src/custom_node.rs | 4 +- bindings/uniffi/src/loader.rs | 6 +- core/engine/src/error.rs | 45 ++++------- .../engine/src/handler/custom_node_adapter.rs | 5 +- core/engine/src/handler/decision.rs | 6 +- core/engine/src/handler/expression/mod.rs | 4 +- core/engine/src/handler/function/mod.rs | 4 +- core/engine/src/handler/function_v1/mod.rs | 1 - core/engine/src/handler/graph.rs | 76 ++++++++++--------- core/engine/src/handler/node.rs | 65 +++++----------- core/engine/src/loader/mod.rs | 2 +- core/engine/src/util/transform_attribute.rs | 1 - core/engine/tests/decision.rs | 14 ++-- core/engine/tests/engine.rs | 14 ++-- core/expression/src/variable/mod.rs | 2 - 23 files changed, 127 insertions(+), 164 deletions(-) diff --git a/bindings/c/src/custom_node.rs b/bindings/c/src/custom_node.rs index 26140484..e98e2758 100644 --- a/bindings/c/src/custom_node.rs +++ b/bindings/c/src/custom_node.rs @@ -49,11 +49,11 @@ impl ZenCustomNodeResult { if let Some(c_error) = maybe_error { let maybe_str = c_error.to_str().unwrap_or("unknown error"); - return Err(anyhow!("{maybe_str}")); + return Err(anyhow!("{maybe_str}").into()); } if self.content.is_null() { - return Err(anyhow!("response not provided")); + return Err(anyhow!("response not provided").into()); } let content_cstr = unsafe { CString::from_raw(self.content) }; diff --git a/bindings/c/src/languages/go.rs b/bindings/c/src/languages/go.rs index 8d48e4bd..1a0541d3 100644 --- a/bindings/c/src/languages/go.rs +++ b/bindings/c/src/languages/go.rs @@ -52,11 +52,11 @@ impl GoCustomNode { impl CustomNodeAdapter for GoCustomNode { async fn handle(&self, request: CustomNodeRequest) -> NodeResult { let Some(handler) = self.handler else { - return Err(anyhow!("go handler not found")); + return Err(anyhow!("go handler not found").into()); }; let Ok(request_value) = serde_json::to_string(&request) else { - return Err(anyhow!("failed to serialize request json")); + return Err(anyhow!("failed to serialize request json").into()); }; let c_request = unsafe { CString::from_vec_unchecked(request_value.into_bytes()) }; diff --git a/bindings/c/src/languages/native.rs b/bindings/c/src/languages/native.rs index e2a7368e..93de29ec 100644 --- a/bindings/c/src/languages/native.rs +++ b/bindings/c/src/languages/native.rs @@ -51,7 +51,7 @@ impl NativeCustomNode { impl CustomNodeAdapter for NativeCustomNode { async fn handle(&self, request: CustomNodeRequest) -> NodeResult { let Ok(request_value) = serde_json::to_string(&request) else { - return Err(anyhow!("failed to serialize request json")); + return Err(anyhow!("failed to serialize request json").into()); }; let c_request = unsafe { CString::from_vec_unchecked(request_value.into_bytes()) }; diff --git a/bindings/c/src/result.rs b/bindings/c/src/result.rs index 4ea82d8c..47644f80 100644 --- a/bindings/c/src/result.rs +++ b/bindings/c/src/result.rs @@ -71,9 +71,9 @@ impl From<&IsolateError> for ZenResult { } } -impl From<&Box> for ZenResult { - fn from(loader_error: &Box) -> Self { - match loader_error.as_ref() { +impl From<&LoaderError> for ZenResult { + fn from(loader_error: &LoaderError) -> Self { + match loader_error { LoaderError::NotFound(key) => { ZenResult::error(ZenError::LoaderKeyNotFound { key: key.clone() }) } diff --git a/bindings/nodejs/src/custom_node.rs b/bindings/nodejs/src/custom_node.rs index dedec446..b3d11060 100644 --- a/bindings/nodejs/src/custom_node.rs +++ b/bindings/nodejs/src/custom_node.rs @@ -2,10 +2,10 @@ use napi::anyhow::anyhow; use napi::bindgen_prelude::Promise; use napi::threadsafe_function::{ErrorStrategy, ThreadsafeFunction}; +use crate::types::{ZenEngineHandlerRequest, ZenEngineHandlerResponse}; use zen_engine::handler::custom_node_adapter::{CustomNodeAdapter, CustomNodeRequest}; use zen_engine::handler::node::{NodeResponse, NodeResult}; - -use crate::types::{ZenEngineHandlerRequest, ZenEngineHandlerResponse}; +use zen_engine::Variable; #[derive(Default)] pub(crate) struct CustomNode { @@ -23,7 +23,7 @@ impl CustomNode { impl CustomNodeAdapter for CustomNode { async fn handle(&self, request: CustomNodeRequest) -> NodeResult { let Some(function) = &self.function else { - return Err(anyhow!("Custom function is undefined")); + return Err(anyhow!("Custom function is undefined").into()); }; let node_data = crate::types::DecisionNode::from(request.node); @@ -41,7 +41,7 @@ impl CustomNodeAdapter for CustomNode { Ok(NodeResponse { output: result.output.into(), - trace_data: result.trace_data, + trace_data: result.trace_data.map(Variable::from), }) } } diff --git a/bindings/nodejs/src/decision.rs b/bindings/nodejs/src/decision.rs index 0e7a0a18..aba951ea 100644 --- a/bindings/nodejs/src/decision.rs +++ b/bindings/nodejs/src/decision.rs @@ -47,13 +47,13 @@ impl ZenDecision { ) .await .map(ZenEngineResponse::from) + .map_err(|e| { + anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())) + }) } }) .await - .map_err(|_| anyhow!("Hook timed out"))? - .map_err(|e| { - anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())) - })?; + .map_err(|_| anyhow!("Hook timed out"))??; Ok(result) } diff --git a/bindings/nodejs/src/engine.rs b/bindings/nodejs/src/engine.rs index 2b2cd702..31d8b955 100644 --- a/bindings/nodejs/src/engine.rs +++ b/bindings/nodejs/src/engine.rs @@ -126,13 +126,13 @@ impl ZenEngine { ) .await .map(ZenEngineResponse::from) + .map_err(|e| { + anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())) + }) } }) .await - .map_err(|_| anyhow!("Hook timed out"))? - .map_err(|e| { - anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())) - })?; + .map_err(|_| anyhow!("Hook timed out"))??; Ok(result) } diff --git a/bindings/nodejs/src/types.rs b/bindings/nodejs/src/types.rs index c55826ef..d6eb9f39 100644 --- a/bindings/nodejs/src/types.rs +++ b/bindings/nodejs/src/types.rs @@ -28,7 +28,7 @@ impl From for ZenEngineTrace { input: value.input.to_value(), output: value.output.to_value(), performance: value.performance, - trace_data: value.trace_data, + trace_data: value.trace_data.map(Value::from), order: value.order, } } diff --git a/bindings/uniffi/src/custom_node.rs b/bindings/uniffi/src/custom_node.rs index 6f402e7c..8a287cbc 100644 --- a/bindings/uniffi/src/custom_node.rs +++ b/bindings/uniffi/src/custom_node.rs @@ -1,6 +1,5 @@ use crate::error::ZenError; use crate::types::{DecisionNode, ZenEngineHandlerRequest, ZenEngineHandlerResponse}; -use serde_json::Value; use uniffi::deps::anyhow::anyhow; use zen_engine::handler::custom_node_adapter::{CustomNodeAdapter, CustomNodeRequest}; use zen_engine::handler::node::{NodeResponse, NodeResult}; @@ -49,7 +48,8 @@ impl CustomNodeAdapter for ZenCustomNodeCallbackWrapper { .try_into() .map_err(|err: ZenError| anyhow!(err))?; - let trace_data: Option = result.trace_data.and_then(|trace| trace.try_into().ok()); + let trace_data: Option = + result.trace_data.and_then(|trace| trace.try_into().ok()); Ok(NodeResponse { output, trace_data }) } diff --git a/bindings/uniffi/src/loader.rs b/bindings/uniffi/src/loader.rs index e21b2e07..2beb4def 100644 --- a/bindings/uniffi/src/loader.rs +++ b/bindings/uniffi/src/loader.rs @@ -29,15 +29,15 @@ impl DecisionLoader for ZenDecisionLoaderCallbackWrapper { let maybe_json_buffer = match self.0.load(key.into()).await { Ok(r) => r, Err(error) => { - return Err(Box::new(LoaderError::Internal { + return Err(LoaderError::Internal { key: key.to_string(), source: anyhow!(error), - })); + }); } }; let Some(json_buffer) = maybe_json_buffer else { - return Err(Box::new(LoaderError::NotFound(key.to_string()))); + return Err(LoaderError::NotFound(key.to_string())); }; let decision_content: DecisionContent = diff --git a/core/engine/src/error.rs b/core/engine/src/error.rs index f5f22673..fdbb0f9e 100644 --- a/core/engine/src/error.rs +++ b/core/engine/src/error.rs @@ -1,30 +1,29 @@ use crate::handler::graph::DecisionGraphValidationError; -use crate::handler::node::NodError; +pub use crate::handler::node::NodeError; use crate::loader::LoaderError; use jsonschema::{ErrorIterator, ValidationError}; use serde::ser::SerializeMap; use serde::{Serialize, Serializer}; use serde_json::{Map, Value}; use std::iter::once; -use std::ops::Deref; use thiserror::Error; #[derive(Debug, Error)] pub enum EvaluationError { #[error("Loader error")] - LoaderError(Box), + LoaderError(LoaderError), #[error("Node error")] - NodeError(Box), + NodeError(NodeError), #[error("Depth limit exceeded")] DepthLimitExceeded, #[error("Invalid graph")] - InvalidGraph(Box), + InvalidGraph(DecisionGraphValidationError), #[error("Validation failed")] - Validation(Box), + Validation(Value), } impl Serialize for EvaluationError { @@ -40,11 +39,11 @@ impl Serialize for EvaluationError { EvaluationError::NodeError(err) => { map.serialize_entry("type", "NodeError")?; - match err.deref() { - NodError::Internal => map.serialize_entry("source", "Internal")?, - NodError::Other(o) => map.serialize_entry("source", &o.to_string())?, - NodError::Display(d) => map.serialize_entry("source", d.as_str())?, - NodError::Node { + match err { + NodeError::Internal => map.serialize_entry("source", "Internal")?, + NodeError::Other(o) => map.serialize_entry("source", &o.to_string())?, + NodeError::Display(d) => map.serialize_entry("source", d.as_str())?, + NodeError::Node { node_id, source, trace, @@ -59,7 +58,7 @@ impl Serialize for EvaluationError { )?; } } - NodError::PartialTrace { trace, message } => { + NodeError::PartialTrace { trace, message } => { map.serialize_entry("source", message.as_str())?; if let Some(trace) = &trace { map.serialize_entry( @@ -72,7 +71,7 @@ impl Serialize for EvaluationError { } EvaluationError::LoaderError(err) => { map.serialize_entry("type", "LoaderError")?; - match err.as_ref() { + match err { LoaderError::Internal { key, source } => { map.serialize_entry("key", key)?; map.serialize_entry("source", &source.to_string())?; @@ -102,20 +101,8 @@ impl From for Box { } } -impl From> for Box { - fn from(error: Box) -> Self { - Box::new(EvaluationError::LoaderError(error)) - } -} - -impl From for Box { - fn from(value: NodError) -> Self { - Box::new(EvaluationError::NodeError(Box::new(value))) - } -} - -impl From> for Box { - fn from(value: Box) -> Self { +impl From for Box { + fn from(value: NodeError) -> Self { Box::new(EvaluationError::NodeError(value)) } } @@ -152,9 +139,7 @@ impl<'a> From> for Box { serde_json::to_value(errors).unwrap_or_default(), ); - Box::new(EvaluationError::Validation(Box::new(Value::Object( - json_map, - )))) + Box::new(EvaluationError::Validation(Value::Object(json_map))) } } diff --git a/core/engine/src/handler/custom_node_adapter.rs b/core/engine/src/handler/custom_node_adapter.rs index 84ae5c7f..f4aea12b 100644 --- a/core/engine/src/handler/custom_node_adapter.rs +++ b/core/engine/src/handler/custom_node_adapter.rs @@ -1,6 +1,5 @@ -use crate::handler::node::{NodError, NodeRequest, NodeResult}; +use crate::handler::node::{NodeError, NodeRequest, NodeResult}; use crate::model::{DecisionNode, DecisionNodeKind}; -use anyhow::anyhow; use json_dotpath::DotPaths; use serde::Serialize; use serde_json::Value; @@ -18,7 +17,7 @@ pub struct NoopCustomNode; impl CustomNodeAdapter for NoopCustomNode { async fn handle(&self, _: CustomNodeRequest) -> NodeResult { - Err(NodError::Internal) + Err(NodeError::Internal) } } diff --git a/core/engine/src/handler/decision.rs b/core/engine/src/handler/decision.rs index 252efc08..f70f9b19 100644 --- a/core/engine/src/handler/decision.rs +++ b/core/engine/src/handler/decision.rs @@ -1,7 +1,7 @@ use crate::handler::custom_node_adapter::CustomNodeAdapter; use crate::handler::function::function::Function; use crate::handler::graph::{DecisionGraph, DecisionGraphConfig}; -use crate::handler::node::{NodError, NodeRequest, NodeResponse, NodeResult}; +use crate::handler::node::{NodeError, NodeRequest, NodeResponse, NodeResult}; use crate::loader::DecisionLoader; use crate::model::DecisionNodeKind; use crate::util::validator_cache::ValidatorCache; @@ -59,7 +59,7 @@ impl DecisionHandle .loader .load(&content.key) .await - .map_err(|_| NodError::Internal)?; + .map_err(|_| NodeError::Internal)?; let sub_tree = DecisionGraph::try_new(DecisionGraphConfig { content: sub_decision, max_depth: self.max_depth, @@ -69,7 +69,7 @@ impl DecisionHandle trace: self.trace, validator_cache: Some(self.validator_cache.clone()), }) - .map_err(|_| NodError::Internal)? + .map_err(|_| NodeError::Internal)? .with_function(self.js_function.clone()); let sub_tree_mutex = Arc::new(Mutex::new(sub_tree)); diff --git a/core/engine/src/handler/expression/mod.rs b/core/engine/src/handler/expression/mod.rs index dc08bd07..be5c3e9a 100644 --- a/core/engine/src/handler/expression/mod.rs +++ b/core/engine/src/handler/expression/mod.rs @@ -4,7 +4,7 @@ use ahash::{HashMap, HashMapExt}; use std::rc::Rc; use std::sync::Arc; -use crate::handler::node::NodError; +use crate::handler::node::NodeError; use anyhow::anyhow; use serde::Serialize; use tokio::sync::Mutex; @@ -73,7 +73,7 @@ impl<'a> ExpressionHandlerInner<'a> { } let value = self.isolate.run_standard(&expression.value).map_err(|_| { - NodError::PartialTrace { + NodeError::PartialTrace { trace: trace_map.as_ref().map(|v| v.to_variable()), message: format!(r#"Failed to evaluate expression: "{}""#, &expression.value), } diff --git a/core/engine/src/handler/function/mod.rs b/core/engine/src/handler/function/mod.rs index cc599056..82b29587 100644 --- a/core/engine/src/handler/function/mod.rs +++ b/core/engine/src/handler/function/mod.rs @@ -6,7 +6,7 @@ use crate::handler::function::error::FunctionResult; use crate::handler::function::function::{Function, HandlerResponse}; use crate::handler::function::module::console::Log; use crate::handler::function::serde::JsValue; -use crate::handler::node::{NodError, NodeRequest, NodeResponse, NodeResult}; +use crate::handler::node::{NodeError, NodeRequest, NodeResponse, NodeResult}; use crate::model::{DecisionNodeKind, FunctionNodeContent}; use crate::ZEN_CONFIG; use ::serde::{Deserialize, Serialize}; @@ -103,7 +103,7 @@ impl FunctionHandler { ms_since_run: start.elapsed().as_millis() as usize, }); - Err(NodError::PartialTrace { + Err(NodeError::PartialTrace { message: e.to_string(), trace: Some(log.to_variable()), }) diff --git a/core/engine/src/handler/function_v1/mod.rs b/core/engine/src/handler/function_v1/mod.rs index acf53031..d7c410b7 100644 --- a/core/engine/src/handler/function_v1/mod.rs +++ b/core/engine/src/handler/function_v1/mod.rs @@ -5,7 +5,6 @@ use crate::handler::node::{NodeRequest, NodeResponse, NodeResult}; use crate::model::{DecisionNodeKind, FunctionNodeContent}; use anyhow::anyhow; use rquickjs::Runtime; -use serde_json::json; use zen_expression::variable::ToVariable; pub(crate) mod runtime; diff --git a/core/engine/src/handler/graph.rs b/core/engine/src/handler/graph.rs index 75f0fbb2..56128991 100644 --- a/core/engine/src/handler/graph.rs +++ b/core/engine/src/handler/graph.rs @@ -7,7 +7,7 @@ use crate::handler::function::module::zen::ZenListener; use crate::handler::function::FunctionHandler; use crate::handler::function_v1; use crate::handler::function_v1::runtime::create_runtime; -use crate::handler::node::{NodError, NodeRequest, PartialTraceError}; +use crate::handler::node::NodeRequest; use crate::handler::table::zen::DecisionTableHandler; use crate::handler::traversal::{GraphWalker, StableDiDecisionGraph}; use crate::loader::DecisionLoader; @@ -143,19 +143,22 @@ impl DecisionGraph< .count() } - pub async fn evaluate(&mut self, context: Variable) -> Result { + pub async fn evaluate( + &mut self, + context: Variable, + ) -> Result { let root_start = Instant::now(); - self.validate().map_err(|e| NodeError { + self.validate().map_err(|e| NodeError::Node { node_id: "".to_string(), source: anyhow!(e).into(), trace: None, })?; if self.iteration >= self.max_depth { - return Err(NodError::Node { + return Err(NodeError::Node { node_id: "".to_string(), - source: Box::new(NodError::Internal), + source: Box::new(NodeError::Internal), trace: None, }); } @@ -215,22 +218,24 @@ impl DecisionGraph< .validator_cache .get_or_insert(validator_key, &json_schema) .await - .map_err(|e| NodeError { - source: NodError::from(e.to_string()), + .map_err(|e| NodeError::Node { + source: NodeError::from(e.to_string()).into(), node_id: node.id.clone(), trace: error_trace(&node_traces), })?; let context_json = context.to_value(); - validator.validate(&context_json).map_err(|e| NodeError { - source: anyhow!(serde_json::to_value( - Into::>::into(e) - ) - .unwrap_or_default()) - .into(), - node_id: node.id.clone(), - trace: error_trace(&node_traces), - })?; + validator + .validate(&context_json) + .map_err(|e| NodeError::Node { + source: anyhow!(serde_json::to_value( + Box::::from(e) + ) + .unwrap_or_default()) + .into(), + node_id: node.id.clone(), + trace: error_trace(&node_traces), + })?; } walker.set_node_data(nid, context.clone()); @@ -255,8 +260,8 @@ impl DecisionGraph< .validator_cache .get_or_insert(validator_key, &json_schema) .await - .map_err(|e| NodeError { - source: NodError::from(e.to_string()), + .map_err(|e| NodeError::Node { + source: NodeError::from(e.to_string()).into(), node_id: node.id.clone(), trace: error_trace(&node_traces), })?; @@ -264,8 +269,8 @@ impl DecisionGraph< let incoming_data_json = incoming_data.to_value(); validator .validate(&incoming_data_json) - .map_err(|e| NodeError { - source: NodError::from(e.to_string()), + .map_err(|e| NodeError::Node { + source: NodeError::from(e.to_string()).into(), node_id: node.id.clone(), trace: error_trace(&node_traces), })?; @@ -283,11 +288,14 @@ impl DecisionGraph< walker.set_node_data(nid, input_data); } DecisionNodeKind::FunctionNode { content } => { - let function = self.get_or_insert_function().await.map_err(|e| NodeError { - source: e.into(), - node_id: node.id.clone(), - trace: error_trace(&node_traces), - })?; + let function = + self.get_or_insert_function() + .await + .map_err(|e| NodeError::Node { + source: e.into(), + node_id: node.id.clone(), + trace: error_trace(&node_traces), + })?; let node_request = NodeRequest { node: node.clone(), @@ -304,7 +312,7 @@ impl DecisionGraph< .handle(node_request.clone()) .await .map_err(|e| { - if let NodError::PartialTrace { trace, message } = &e { + if let NodeError::PartialTrace { trace, .. } = &e { trace!({ input: node_request.input.clone(), output: Variable::Null, @@ -312,14 +320,14 @@ impl DecisionGraph< }); } - NodeError { + NodeError::Node { source: e.into(), node_id: node.id.clone(), trace: error_trace(&node_traces), } })?, FunctionNodeContent::Version1(_) => { - let runtime = create_runtime().map_err(|e| NodeError { + let runtime = create_runtime().map_err(|e| NodeError::Node { source: e.into(), node_id: node.id.clone(), trace: error_trace(&node_traces), @@ -328,7 +336,7 @@ impl DecisionGraph< function_v1::FunctionHandler::new(self.trace, runtime) .handle(node_request.clone()) .await - .map_err(|e| NodeError { + .map_err(|e| NodeError::Node { source: e.into(), node_id: node.id.clone(), trace: error_trace(&node_traces), @@ -363,7 +371,7 @@ impl DecisionGraph< ) .handle(node_request.clone()) .await - .map_err(|e| NodeError { + .map_err(|e| NodeError::Node { source: e.into(), node_id: node.id.to_string(), trace: error_trace(&node_traces), @@ -389,7 +397,7 @@ impl DecisionGraph< let res = DecisionTableHandler::new(self.trace) .handle(node_request.clone()) .await - .map_err(|e| NodeError { + .map_err(|e| NodeError::Node { node_id: node.id.clone(), source: e.into(), trace: error_trace(&node_traces), @@ -416,7 +424,7 @@ impl DecisionGraph< .handle(node_request.clone()) .await .map_err(|e| { - if let NodError::PartialTrace { trace, message } = &e { + if let NodeError::PartialTrace { trace, .. } = &e { trace!({ input: node_request.input.clone(), output: Variable::Null, @@ -424,7 +432,7 @@ impl DecisionGraph< }); } - NodeError { + NodeError::Node { node_id: node.id.clone(), source: e.into(), trace: error_trace(&node_traces), @@ -452,7 +460,7 @@ impl DecisionGraph< .adapter .handle(CustomNodeRequest::try_from(node_request.clone()).unwrap()) .await - .map_err(|e| NodeError { + .map_err(|e| NodeError::Node { node_id: node.id.clone(), source: e.into(), trace: error_trace(&node_traces), diff --git a/core/engine/src/handler/node.rs b/core/engine/src/handler/node.rs index 2a0f722e..1bc4da8a 100644 --- a/core/engine/src/handler/node.rs +++ b/core/engine/src/handler/node.rs @@ -18,42 +18,17 @@ pub struct NodeRequest { pub node: Arc, } -#[derive(Debug)] -pub struct NodeError { - pub node_id: String, - pub trace: Option, - pub source: NodError, -} - -impl Display for NodeError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -#[derive(Debug)] -pub(crate) struct PartialTraceError { - pub trace: Option, - pub message: String, -} - -impl Display for PartialTraceError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.message) - } -} - -pub type NodeResult = Result; +pub type NodeResult = Result; #[derive(Debug)] -pub enum NodError { +pub enum NodeError { Internal, Other(Box), Display(String), // For non-Error types that implement Display Node { node_id: String, trace: Option, - source: Box, + source: Box, }, PartialTrace { trace: Option, @@ -61,7 +36,7 @@ pub enum NodError { }, } -impl NodError { +impl NodeError { /// Convert any error type to NodError pub fn from_error(error: E) -> Self { Self::Other(Box::new(error)) @@ -78,16 +53,16 @@ impl NodError { } } -impl Display for NodError { +impl Display for NodeError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - NodError::Internal => write!(f, "Internal error occurred"), - NodError::Other(err) => write!(f, "{}", err), - NodError::Display(msg) => write!(f, "{}", msg), - NodError::Node { source, .. } => { + NodeError::Internal => write!(f, "Internal error occurred"), + NodeError::Other(err) => write!(f, "{}", err), + NodeError::Display(msg) => write!(f, "{}", msg), + NodeError::Node { source, .. } => { write!(f, "{}", source) } - NodError::PartialTrace { trace, message } => { + NodeError::PartialTrace { trace, message } => { if let Some(var) = trace { write!(f, "{} (trace: {:?})", message, var) } else { @@ -98,24 +73,20 @@ impl Display for NodError { } } -impl From for NodError { +impl From for Box { fn from(value: anyhow::Error) -> Self { - Self::Other(value.into()) + Box::new(NodeError::Other(value.into())) } } -impl From for NodError { - fn from(value: String) -> Self { - Self::Display(value) +impl From for NodeError { + fn from(value: anyhow::Error) -> Self { + Self::Other(value.into()) } } -impl From for NodError { - fn from(value: NodeError) -> Self { - Self::Node { - source: Box::new(value.source), - trace: value.trace.clone(), - node_id: value.node_id, - } +impl From for NodeError { + fn from(value: String) -> Self { + Self::Display(value) } } diff --git a/core/engine/src/loader/mod.rs b/core/engine/src/loader/mod.rs index 4cb8a27b..cdf6f663 100644 --- a/core/engine/src/loader/mod.rs +++ b/core/engine/src/loader/mod.rs @@ -18,7 +18,7 @@ mod filesystem; mod memory; mod noop; -pub type LoaderResult = Result>; +pub type LoaderResult = Result; pub type LoaderResponse = LoaderResult>; /// Trait used for implementing a loader for decisions diff --git a/core/engine/src/util/transform_attribute.rs b/core/engine/src/util/transform_attribute.rs index 213cad12..888476be 100644 --- a/core/engine/src/util/transform_attribute.rs +++ b/core/engine/src/util/transform_attribute.rs @@ -1,7 +1,6 @@ use crate::handler::node::{NodeResponse, NodeResult}; use crate::model::{TransformAttributes, TransformExecutionMode}; use anyhow::Context; -use serde_json::Value; use std::future::Future; use zen_expression::{Isolate, Variable}; diff --git a/core/engine/tests/decision.rs b/core/engine/tests/decision.rs index cc5609b0..a487fb6b 100644 --- a/core/engine/tests/decision.rs +++ b/core/engine/tests/decision.rs @@ -3,7 +3,7 @@ use serde_json::json; use std::ops::Deref; use std::sync::Arc; use tokio::runtime::Builder; -use zen_engine::{Decision, DecisionGraphValidationError, EvaluationError}; +use zen_engine::{Decision, DecisionGraphValidationError, EvaluationError, NodeError}; mod support; @@ -28,9 +28,11 @@ async fn decision_from_content_recursive() { let context = json!({}); let result = decision.evaluate(context.clone().into()).await; match result.unwrap_err().deref() { - EvaluationError::NodeError(e) => { - assert_eq!(e.node_id, "0b8dcf6b-fc04-47cb-bf82-bda764e6c09b"); - assert!(e.source.to_string().contains("Loader failed")); + EvaluationError::NodeError(NodeError::Node { + node_id, source, .. + }) => { + assert_eq!(node_id, "0b8dcf6b-fc04-47cb-bf82-bda764e6c09b"); + assert!(source.to_string().contains("Loader failed")); } _ => assert!(false, "Depth limit not exceeded"), } @@ -38,8 +40,8 @@ async fn decision_from_content_recursive() { let with_loader = decision.with_loader(Arc::new(create_fs_loader())); let new_result = with_loader.evaluate(context.clone().into()).await; match new_result.unwrap_err().deref() { - EvaluationError::NodeError(e) => { - assert_eq!(e.source.to_string(), "Depth limit exceeded") + EvaluationError::NodeError(NodeError::Node { source, .. }) => { + assert_eq!(source.to_string(), "Depth limit exceeded") } _ => assert!(false, "Depth limit not exceeded"), } diff --git a/core/engine/tests/engine.rs b/core/engine/tests/engine.rs index c0337dff..90a4845e 100644 --- a/core/engine/tests/engine.rs +++ b/core/engine/tests/engine.rs @@ -9,8 +9,8 @@ use std::sync::Arc; use tokio::runtime::Builder; use zen_engine::loader::{LoaderError, MemoryLoader}; use zen_engine::model::{DecisionContent, DecisionNode, DecisionNodeKind, FunctionNodeContent}; -use zen_engine::Variable; use zen_engine::{DecisionEngine, EvaluationError, EvaluationOptions}; +use zen_engine::{NodeError, Variable}; mod support; @@ -112,9 +112,11 @@ async fn engine_errors() { .evaluate("infinite-function.json", json!({}).into()) .await; match infinite_fn.unwrap_err().deref() { - EvaluationError::NodeError(e) => { - assert_eq!(e.node_id, "e0fd96d0-44dc-4f0e-b825-06e56b442d78"); - assert!(e.source.to_string().contains("interrupted")); + EvaluationError::NodeError(NodeError::Node { + node_id, source, .. + }) => { + assert_eq!(node_id, "e0fd96d0-44dc-4f0e-b825-06e56b442d78"); + assert!(source.to_string().contains("interrupted")); } _ => assert!(false, "Wrong error type"), } @@ -123,8 +125,8 @@ async fn engine_errors() { .evaluate("recursive-table1.json", json!({}).into()) .await; match recursive.unwrap_err().deref() { - EvaluationError::NodeError(e) => { - assert_eq!(e.source.to_string(), "Depth limit exceeded") + EvaluationError::NodeError(NodeError::Node { source, .. }) => { + assert_eq!(source.to_string(), "Depth limit exceeded") } _ => assert!(false, "Depth limit not exceeded"), } diff --git a/core/expression/src/variable/mod.rs b/core/expression/src/variable/mod.rs index b22b4cf4..e6b4ac9e 100644 --- a/core/expression/src/variable/mod.rs +++ b/core/expression/src/variable/mod.rs @@ -1,4 +1,2 @@ -use std::fmt::{Debug, Display}; - pub use zen_types::variable::{DynamicVariable, ToVariable, Variable, VariableDeserializer}; pub use zen_types::variable_type::VariableType; From d2e26ddca7a905359f553c36af2f63ed73e90e38 Mon Sep 17 00:00:00 2001 From: Stefan Date: Sun, 17 Aug 2025 21:02:41 +0200 Subject: [PATCH 03/14] add deserialization --- core/engine/Cargo.toml | 1 - core/engine/src/error.rs | 4 +- .../engine/src/handler/custom_node_adapter.rs | 4 +- core/engine/src/handler/decision.rs | 9 +- core/engine/src/handler/expression/mod.rs | 2 +- core/engine/src/handler/function/function.rs | 3 +- core/engine/src/handler/function/mod.rs | 21 +- .../src/handler/function/module/console.rs | 2 +- core/engine/src/handler/function_v1/mod.rs | 4 +- core/engine/src/handler/function_v1/script.rs | 5 +- core/engine/src/handler/graph.rs | 40 ++- core/engine/src/handler/node.rs | 8 +- core/engine/src/handler/table/mod.rs | 3 +- core/engine/src/handler/table/zen.rs | 2 +- core/expression/src/lib.rs | 2 - core/expression/src/variable/mod.rs | 7 +- core/macros/Cargo.toml | 1 + core/macros/src/lib.rs | 2 +- core/macros/src/to_variable.rs | 253 ++++++++------ core/types/src/variable/mod.rs | 7 +- core/types/src/variable/ref_deser.rs | 313 ++++++++++++++++++ core/types/src/variable_type/mod.rs | 1 + 22 files changed, 551 insertions(+), 143 deletions(-) create mode 100644 core/types/src/variable/ref_deser.rs diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 39d43c48..66bea3da 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -27,7 +27,6 @@ rquickjs = { version = "0.9", features = ["macro", "loader", "rust-alloc", "futu jsonschema = "0.29" zen-expression = { path = "../expression", version = "0.49.1" } zen-tmpl = { path = "../template", version = "0.49.1" } -zen-types = { path = "../types" } [dev-dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } diff --git a/core/engine/src/error.rs b/core/engine/src/error.rs index fdbb0f9e..fb4e396a 100644 --- a/core/engine/src/error.rs +++ b/core/engine/src/error.rs @@ -54,7 +54,7 @@ impl Serialize for EvaluationError { if let Some(trace) = &trace { map.serialize_entry( "trace", - &serde_json::to_string(&trace.serialize_ref()).unwrap(), + &serde_json::to_value(&trace.serialize_ref()).unwrap(), )?; } } @@ -63,7 +63,7 @@ impl Serialize for EvaluationError { if let Some(trace) = &trace { map.serialize_entry( "trace", - &serde_json::to_string(&trace.serialize_ref()).unwrap(), + &serde_json::to_value(&trace.serialize_ref()).unwrap(), )?; } } diff --git a/core/engine/src/handler/custom_node_adapter.rs b/core/engine/src/handler/custom_node_adapter.rs index f4aea12b..9a0711f2 100644 --- a/core/engine/src/handler/custom_node_adapter.rs +++ b/core/engine/src/handler/custom_node_adapter.rs @@ -17,7 +17,9 @@ pub struct NoopCustomNode; impl CustomNodeAdapter for NoopCustomNode { async fn handle(&self, _: CustomNodeRequest) -> NodeResult { - Err(NodeError::Internal) + Err(NodeError::Display( + "Custom node handler not provided".to_string(), + )) } } diff --git a/core/engine/src/handler/decision.rs b/core/engine/src/handler/decision.rs index f70f9b19..97735d70 100644 --- a/core/engine/src/handler/decision.rs +++ b/core/engine/src/handler/decision.rs @@ -1,6 +1,6 @@ use crate::handler::custom_node_adapter::CustomNodeAdapter; use crate::handler::function::function::Function; -use crate::handler::graph::{DecisionGraph, DecisionGraphConfig}; +use crate::handler::graph::{error_trace, DecisionGraph, DecisionGraphConfig}; use crate::handler::node::{NodeError, NodeRequest, NodeResponse, NodeResult}; use crate::loader::DecisionLoader; use crate::model::DecisionNodeKind; @@ -11,7 +11,6 @@ use std::pin::Pin; use std::rc::Rc; use std::sync::Arc; use tokio::sync::Mutex; -use zen_expression::variable::ToVariable; pub struct DecisionHandler { trace: bool, @@ -59,7 +58,7 @@ impl DecisionHandle .loader .load(&content.key) .await - .map_err(|_| NodeError::Internal)?; + .map_err(|err| NodeError::Display(err.to_string()))?; let sub_tree = DecisionGraph::try_new(DecisionGraphConfig { content: sub_decision, max_depth: self.max_depth, @@ -69,7 +68,7 @@ impl DecisionHandle trace: self.trace, validator_cache: Some(self.validator_cache.clone()), }) - .map_err(|_| NodeError::Internal)? + .map_err(|err| NodeError::Display(err.to_string()))? .with_function(self.js_function.clone()); let sub_tree_mutex = Arc::new(Mutex::new(sub_tree)); @@ -85,7 +84,7 @@ impl DecisionHandle sub_tree_ref.reset_graph(); sub_tree_ref.evaluate(input).await.map(|r| NodeResponse { output: r.result, - trace_data: Some(r.trace.to_variable()), + trace_data: error_trace(&r.trace), }) } }) diff --git a/core/engine/src/handler/expression/mod.rs b/core/engine/src/handler/expression/mod.rs index be5c3e9a..d6caf068 100644 --- a/core/engine/src/handler/expression/mod.rs +++ b/core/engine/src/handler/expression/mod.rs @@ -9,7 +9,7 @@ use anyhow::anyhow; use serde::Serialize; use tokio::sync::Mutex; use zen_expression::variable::{ToVariable, Variable}; -use zen_expression::{Isolate, ToVariable}; +use zen_expression::Isolate; pub struct ExpressionHandler { trace: bool, diff --git a/core/engine/src/handler/function/function.rs b/core/engine/src/handler/function/function.rs index fc62256e..78b8805e 100644 --- a/core/engine/src/handler/function/function.rs +++ b/core/engine/src/handler/function/function.rs @@ -9,8 +9,7 @@ use crate::handler::function::serde::JsValue; use rquickjs::promise::MaybePromise; use rquickjs::{async_with, AsyncContext, AsyncRuntime, CatchResultExt, Ctx, Module}; use serde::{Deserialize, Serialize}; -use zen_expression::variable::Variable; -use zen_expression::ToVariable; +use zen_expression::variable::{ToVariable, Variable}; pub struct FunctionConfig { pub(crate) listeners: Option>>, diff --git a/core/engine/src/handler/function/mod.rs b/core/engine/src/handler/function/mod.rs index 82b29587..98a737c1 100644 --- a/core/engine/src/handler/function/mod.rs +++ b/core/engine/src/handler/function/mod.rs @@ -35,6 +35,12 @@ pub struct FunctionHandler { max_duration: Duration, } +#[derive(ToVariable)] +#[serde(rename_all = "camelCase")] +struct FunctionTrace { + pub log: Vec, +} + impl FunctionHandler { pub fn new(function: Rc, trace: bool, iteration: u8, max_depth: u8) -> Self { let max_duration_millis = ZEN_CONFIG.function_timeout_millis.load(Ordering::Relaxed); @@ -58,9 +64,9 @@ impl FunctionHandler { }?; let start = std::time::Instant::now(); - // if content.omit_nodes { - request.input.dot_remove("$nodes"); - // } + if content.omit_nodes { + request.input.dot_remove("$nodes"); + } let module_name = self .function @@ -93,7 +99,12 @@ impl FunctionHandler { Ok(NodeResponse { output: response.data, - trace_data: self.trace.then(|| response.logs.to_variable()), + trace_data: self.trace.then(|| { + FunctionTrace { + log: response.logs.clone(), + } + .to_variable() + }), }) } Err(e) => { @@ -105,7 +116,7 @@ impl FunctionHandler { Err(NodeError::PartialTrace { message: e.to_string(), - trace: Some(log.to_variable()), + trace: Some(FunctionTrace { log }.to_variable()), }) } } diff --git a/core/engine/src/handler/function/module/console.rs b/core/engine/src/handler/function/module/console.rs index 0d7249a9..59e8ca6b 100644 --- a/core/engine/src/handler/function/module/console.rs +++ b/core/engine/src/handler/function/module/console.rs @@ -8,7 +8,7 @@ use crate::handler::function::listener::{RuntimeEvent, RuntimeListener}; use rquickjs::prelude::Rest; use rquickjs::{Ctx, Object, Value}; use serde::{Deserialize, Serialize}; -use zen_expression::ToVariable; +use zen_expression::variable::ToVariable; pub(crate) struct ConsoleListener; diff --git a/core/engine/src/handler/function_v1/mod.rs b/core/engine/src/handler/function_v1/mod.rs index d7c410b7..79dcd6de 100644 --- a/core/engine/src/handler/function_v1/mod.rs +++ b/core/engine/src/handler/function_v1/mod.rs @@ -42,8 +42,8 @@ impl FunctionHandler { let response = result_response?; Ok(NodeResponse { - output: response.output, - trace_data: self.trace.then(|| response.log.to_variable()), + output: response.output.clone(), + trace_data: self.trace.then(|| response.to_variable()), }) } } diff --git a/core/engine/src/handler/function_v1/script.rs b/core/engine/src/handler/function_v1/script.rs index 817748fd..358d285e 100644 --- a/core/engine/src/handler/function_v1/script.rs +++ b/core/engine/src/handler/function_v1/script.rs @@ -5,11 +5,12 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use std::fmt::Debug; use std::rc::Rc; -use zen_expression::variable::Variable; +use zen_expression::variable::{ToVariable, Variable}; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, ToVariable, Deserialize)] #[serde(rename_all = "camelCase")] pub struct EvaluateResponse { + #[serde(skip)] pub output: Variable, pub log: Vec, } diff --git a/core/engine/src/handler/graph.rs b/core/engine/src/handler/graph.rs index 56128991..ab39c00d 100644 --- a/core/engine/src/handler/graph.rs +++ b/core/engine/src/handler/graph.rs @@ -19,14 +19,13 @@ use anyhow::anyhow; use petgraph::algo::is_cyclic_directed; use serde::ser::SerializeMap; use serde::{Deserialize, Serialize, Serializer}; -use serde_json::Value; +use serde_json::{Map, Value}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::rc::Rc; use std::sync::Arc; use std::time::Instant; use thiserror::Error; use zen_expression::variable::{ToVariable, Variable}; -use zen_expression::ToVariable; pub struct DecisionGraph { initial_graph: StableDiDecisionGraph, @@ -158,7 +157,7 @@ impl DecisionGraph< if self.iteration >= self.max_depth { return Err(NodeError::Node { node_id: "".to_string(), - source: Box::new(NodeError::Internal), + source: Box::new(NodeError::Display("Depth limit exceeded".to_string())), trace: None, }); } @@ -540,6 +539,32 @@ pub struct DecisionGraphResponse { pub trace: Option>, } +impl DecisionGraphResponse { + pub fn serialize_ref(&self) -> Value { + let mut map = Map::with_capacity(3); + map.insert( + "performance".to_string(), + Value::String(self.performance.clone()), + ); + map.insert("result".to_string(), self.result.to_value()); + + if let Some(trace) = &self.trace { + let trace_map = trace + .iter() + .map(|(k, v)| (Rc::from(k.as_str()), v.to_variable())) + .collect::, Variable>>(); + + let joined_variable = Variable::from_object(trace_map); + map.insert( + "trace".to_string(), + serde_json::to_value(joined_variable).unwrap_or_default(), + ); + } + + Value::Object(map) + } +} + #[derive(Debug, Clone, Serialize, Deserialize, ToVariable)] #[serde(rename_all = "camelCase")] pub struct DecisionGraphTrace { @@ -553,7 +578,14 @@ pub struct DecisionGraphTrace { } pub(crate) fn error_trace(trace: &Option>) -> Option { - trace.as_ref().map(|s| s.to_variable()) + trace.as_ref().map(|s| { + s.values().for_each(|v| { + v.input.dot_remove("$nodes"); + v.output.dot_remove("$nodes"); + }); + + s.to_variable() + }) } fn create_validator_cache_key(content: &Value) -> u64 { diff --git a/core/engine/src/handler/node.rs b/core/engine/src/handler/node.rs index 1bc4da8a..c28ef4f1 100644 --- a/core/engine/src/handler/node.rs +++ b/core/engine/src/handler/node.rs @@ -62,12 +62,8 @@ impl Display for NodeError { NodeError::Node { source, .. } => { write!(f, "{}", source) } - NodeError::PartialTrace { trace, message } => { - if let Some(var) = trace { - write!(f, "{} (trace: {:?})", message, var) - } else { - write!(f, "{}", message) - } + NodeError::PartialTrace { message, .. } => { + write!(f, "{}", message) } } } diff --git a/core/engine/src/handler/table/mod.rs b/core/engine/src/handler/table/mod.rs index b4ed3b3c..71967534 100644 --- a/core/engine/src/handler/table/mod.rs +++ b/core/engine/src/handler/table/mod.rs @@ -1,7 +1,6 @@ pub mod zen; -use zen_expression::variable::Variable; -use zen_expression::ToVariable; +use zen_expression::variable::{ToVariable, Variable}; #[derive(Debug, Clone, ToVariable)] pub(crate) enum RowOutputKind { diff --git a/core/engine/src/handler/table/zen.rs b/core/engine/src/handler/table/zen.rs index 0938fae3..b582e027 100644 --- a/core/engine/src/handler/table/zen.rs +++ b/core/engine/src/handler/table/zen.rs @@ -8,7 +8,7 @@ use crate::model::{DecisionNodeKind, DecisionTableContent, DecisionTableHitPolic use serde::Serialize; use tokio::sync::Mutex; use zen_expression::variable::{ToVariable, Variable}; -use zen_expression::{Isolate, ToVariable}; +use zen_expression::Isolate; #[derive(Debug, Serialize, ToVariable)] struct RowResult { diff --git a/core/expression/src/lib.rs b/core/expression/src/lib.rs index 1d5760e0..7f54d584 100644 --- a/core/expression/src/lib.rs +++ b/core/expression/src/lib.rs @@ -69,8 +69,6 @@ pub mod validate; pub mod variable; pub mod vm; -pub use zen_macros::ToVariable; - pub use exports::{ compile_expression, compile_unary_expression, evaluate_expression, evaluate_unary_expression, }; diff --git a/core/expression/src/variable/mod.rs b/core/expression/src/variable/mod.rs index e6b4ac9e..ef41a48d 100644 --- a/core/expression/src/variable/mod.rs +++ b/core/expression/src/variable/mod.rs @@ -1,2 +1,5 @@ -pub use zen_types::variable::{DynamicVariable, ToVariable, Variable, VariableDeserializer}; -pub use zen_types::variable_type::VariableType; +pub use zen_types::rcvalue::*; +pub use zen_types::variable::*; +pub use zen_types::variable_type::*; + +pub use zen_macros::ToVariable; diff --git a/core/macros/Cargo.toml b/core/macros/Cargo.toml index 78d892e3..99257dd8 100644 --- a/core/macros/Cargo.toml +++ b/core/macros/Cargo.toml @@ -11,3 +11,4 @@ proc-macro = true proc-macro2 = "1" quote = "1" syn = { version = "2", features = ["full"] } +serde_derive_internals = "0.29" diff --git a/core/macros/src/lib.rs b/core/macros/src/lib.rs index dffbbd3c..109b12cf 100644 --- a/core/macros/src/lib.rs +++ b/core/macros/src/lib.rs @@ -2,7 +2,7 @@ use proc_macro::TokenStream; mod to_variable; -#[proc_macro_derive(ToVariable)] +#[proc_macro_derive(ToVariable, attributes(serde))] pub fn derive_to_variable(input: TokenStream) -> TokenStream { to_variable::to_variable_impl(input) } diff --git a/core/macros/src/to_variable.rs b/core/macros/src/to_variable.rs index e92a8ae9..aad1f08f 100644 --- a/core/macros/src/to_variable.rs +++ b/core/macros/src/to_variable.rs @@ -1,160 +1,211 @@ use proc_macro::TokenStream; use quote::quote; -use syn::{Data, DeriveInput, Fields, Variant, parse_macro_input}; +use syn::parse_macro_input; pub fn to_variable_impl(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - let name = &input.ident; - - match &input.data { - Data::Struct(data_struct) => generate_struct_impl(name, data_struct), - Data::Enum(data_enum) => generate_enum_impl(name, data_enum), - _ => syn::Error::new_spanned(&input, "ToVariable only supports structs and enums") - .to_compile_error() - .into(), + let mut input = parse_macro_input!(input as syn::DeriveInput); + + serde_derive_internals::replace_receiver(&mut input); + + let ctxt = serde_derive_internals::Ctxt::new(); + let container = match serde_derive_internals::ast::Container::from_ast( + &ctxt, + &input, + serde_derive_internals::Derive::Serialize, + ) { + Some(container) => container, + None => return ctxt.check().unwrap_err().into_compile_error().into(), + }; + + if let Err(err) = ctxt.check() { + return err.into_compile_error().into(); } -} -fn generate_struct_impl(name: &syn::Ident, data_struct: &syn::DataStruct) -> TokenStream { - let fields = match &data_struct.fields { - Fields::Named(fields_named) => &fields_named.named, - _ => { - return syn::Error::new_spanned( - name, - "ToVariable only supports structs with named fields", - ) - .to_compile_error() - .into(); + let ident = &container.ident; + let (impl_generics, ty_generics, where_clause) = container.generics.split_for_impl(); + + let body = match &container.data { + serde_derive_internals::ast::Data::Struct(_, fields) => generate_struct_body(fields), + serde_derive_internals::ast::Data::Enum(variants) => { + generate_enum_body(variants, &container) } }; - let field_count = fields.len(); - let field_mappings = fields.iter().map(|field| { - let field_name = field.ident.as_ref().unwrap(); - let field_name_str = field_name.to_string(); + let impl_block = quote! { + #[automatically_derived] + impl #impl_generics _ToVariable for #ident #ty_generics #where_clause { + fn to_variable(&self) -> _Variable { + #body + } + } + }; + + quote! { + #[doc(hidden)] + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications, clippy::absolute_paths)] + const _: () = { + extern crate zen_expression as _zen_expression; + + use _zen_expression::variable::{Variable as _Variable, VariableMap as _VariableMap, VariableMapExt, ToVariable as _ToVariable}; + use ::std::rc::Rc as _Rc; + + #impl_block + }; + }.into() +} + +fn generate_struct_body(fields: &[serde_derive_internals::ast::Field]) -> proc_macro2::TokenStream { + let active_fields: Vec<_> = fields + .iter() + .filter(|field| !field.attrs.skip_serializing()) + .collect(); + + let field_count = active_fields.len(); + + let field_mappings = active_fields.iter().map(|field| { + let field_ident = match &field.member { + syn::Member::Named(ident) => ident, + syn::Member::Unnamed(_) => panic!("ToVariable only supports named fields"), + }; + + let serialized_name = field.attrs.name().serialize_name(); quote! { map.insert( - std::rc::Rc::from(#field_name_str), - (&self.#field_name).to_variable() + _Rc::from(#serialized_name), + self.#field_ident.to_variable() ); } }); - let expanded = quote! { - impl zen_expression::variable::ToVariable for #name { - fn to_variable(&self) -> zen_expression::Variable { - use ahash::{HashMap, HashMapExt}; - use std::rc::Rc; + quote! { + let mut map = _VariableMap::with_capacity(#field_count); + #(#field_mappings)* + _Variable::from_object(map) + } +} - let mut map = HashMap::with_capacity(#field_count); - #(#field_mappings)* - zen_expression::Variable::from_object(map) - } - } - }; +fn generate_enum_body( + variants: &[serde_derive_internals::ast::Variant], + container: &serde_derive_internals::ast::Container, +) -> proc_macro2::TokenStream { + let enum_ident = &container.ident; - TokenStream::from(expanded) -} + let active_variants: Vec<_> = variants + .iter() + .filter(|variant| !variant.attrs.skip_serializing()) + .collect(); -fn generate_enum_impl(name: &syn::Ident, data_enum: &syn::DataEnum) -> TokenStream { - let variants = data_enum - .variants + let variant_arms = active_variants .iter() - .map(|variant| generate_variant_match(name, variant)); - - let expanded = quote! { - impl zen_expression::variable::ToVariable for #name { - fn to_variable(&self) -> zen_expression::Variable { - use ahash::{HashMap, HashMapExt}; - use std::rc::Rc; - use zen_expression::Variable; - use zen_expression::variable::{ToVariable}; - - match self { - #(#variants)* - } - } - } - }; + .map(|variant| generate_variant_arm(enum_ident, variant, container)); - TokenStream::from(expanded) + quote! { + match self { + #(#variant_arms)* + } + } } -fn generate_variant_match(enum_name: &syn::Ident, variant: &Variant) -> proc_macro2::TokenStream { - let variant_name = &variant.ident; - let variant_str = variant_name.to_string(); +fn generate_variant_arm( + enum_ident: &syn::Ident, + variant: &serde_derive_internals::ast::Variant, + container: &serde_derive_internals::ast::Container, +) -> proc_macro2::TokenStream { + let variant_ident = &variant.ident; + + let variant_name = variant.attrs.name().serialize_name(); + let rename_rule = container.attrs.rename_all_rules().serialize; + let type_key = rename_rule.apply_to_field("type"); + let value_key = rename_rule.apply_to_field("value"); - match &variant.fields { - // Unit variant: MyEnum::Variant - Fields::Unit => { + match variant.style { + serde_derive_internals::ast::Style::Unit => { quote! { - #enum_name::#variant_name => Variable::String(Rc::from(#variant_str)), + #enum_ident::#variant_ident => { + _Variable::String(_Rc::from(#variant_name)) + } } } - // Tuple variant: MyEnum::Variant(T1, T2, ...) - Fields::Unnamed(fields) => { - let field_count = fields.unnamed.len(); + serde_derive_internals::ast::Style::Newtype => { + quote! { + #enum_ident::#variant_ident(value) => { + let mut map = _VariableMap::with_capacity(2); + map.insert(_Rc::from(#type_key), _Variable::String(_Rc::from(#variant_name))); + map.insert(_Rc::from(#value_key), value.to_variable()); + _Variable::from_object(map) + } + } + } + + serde_derive_internals::ast::Style::Tuple => { + let field_count = variant.fields.len(); let field_patterns: Vec<_> = (0..field_count) .map(|i| quote::format_ident!("field_{}", i)) .collect(); if field_count == 1 { - // Single field - flatten directly with type quote! { - #enum_name::#variant_name(#(#field_patterns),*) => { - let mut map = HashMap::with_capacity(2); - map.insert(Rc::from("type"), Variable::String(Rc::from(#variant_str))); - map.insert(Rc::from("value"), (#(#field_patterns)*).to_variable()); - Variable::from_object(map) - }, + #enum_ident::#variant_ident(#(#field_patterns),*) => { + let mut map = _VariableMap::with_capacity(2); + map.insert(_Rc::from(#type_key), _Variable::String(_Rc::from(#variant_name))); + map.insert(_Rc::from(#value_key), (#(#field_patterns)*).to_variable()); + _Variable::from_object(map) + } } } else { - // Multiple fields - flatten as indexed fields let field_mappings = field_patterns.iter().enumerate().map(|(i, pattern)| { - let field_name = format!("field_{}", i); + let field_key = rename_rule.apply_to_field(&format!("field_{}", i)); quote! { - map.insert(Rc::from(#field_name), (#pattern).to_variable()); + map.insert(_Rc::from(#field_key), (#pattern).to_variable()); } }); - let total_capacity = field_count + 1; // +1 for "type" - quote! { - #enum_name::#variant_name(#(#field_patterns),*) => { - let mut map = HashMap::with_capacity(#total_capacity); - map.insert(Rc::from("type"), Variable::String(Rc::from(#variant_str))); + #enum_ident::#variant_ident(#(#field_patterns),*) => { + let mut map = _VariableMap::with_capacity(#field_count + 1); + map.insert(_Rc::from(#type_key), _Variable::String(_Rc::from(#variant_name))); #(#field_mappings)* - Variable::from_object(map) - }, + _Variable::from_object(map) + } } } } - Fields::Named(fields) => { - let field_count = fields.named.len() + 1; // +1 for the "type" field - let field_mappings = fields.named.iter().map(|field| { - let field_name = field.ident.as_ref().unwrap(); - let field_name_str = field_name.to_string(); + serde_derive_internals::ast::Style::Struct => { + let active_fields: Vec<_> = variant + .fields + .iter() + .filter(|field| !field.attrs.skip_serializing()) + .collect(); + + let field_mappings = active_fields.iter().map(|field| { + let field_ident = match &field.member { + syn::Member::Named(ident) => ident, + syn::Member::Unnamed(_) => panic!("Unexpected unnamed field in struct variant"), + }; + + let field_name = field.attrs.name().serialize_name(); quote! { - map.insert(Rc::from(#field_name_str), (#field_name).to_variable()); + map.insert(_Rc::from(#field_name), #field_ident.to_variable()); } }); - let field_patterns = fields.named.iter().map(|field| { - let field_name = field.ident.as_ref().unwrap(); - quote! { #field_name } + let field_patterns = active_fields.iter().map(|field| match &field.member { + syn::Member::Named(ident) => quote! { #ident }, + syn::Member::Unnamed(_) => panic!("Unexpected unnamed field in struct variant"), }); + let field_count = active_fields.len() + 1; quote! { - #enum_name::#variant_name { #(#field_patterns),* } => { - let mut map = HashMap::with_capacity(#field_count); - map.insert(Rc::from("type"), Variable::String(Rc::from(#variant_str))); + #enum_ident::#variant_ident { #(#field_patterns),* } => { + let mut map = _VariableMap::with_capacity(#field_count); + map.insert(_Rc::from(#type_key), _Variable::String(_Rc::from(#variant_name))); #(#field_mappings)* - Variable::from_object(map) - }, + _Variable::from_object(map) + } } } } diff --git a/core/types/src/variable/mod.rs b/core/types/src/variable/mod.rs index 7fca38d2..8da8a435 100644 --- a/core/types/src/variable/mod.rs +++ b/core/types/src/variable/mod.rs @@ -17,18 +17,21 @@ pub use impls::ToVariable; mod conv; mod de; mod impls; +mod ref_deser; mod ref_ser; mod ser; pub(crate) type RcCell = Rc>; +pub type VariableMap = HashMap, Variable>; + pub enum Variable { Null, Bool(bool), Number(Decimal), String(Rc), Array(RcCell>), - Object(RcCell, Variable>>), + Object(RcCell), Dynamic(Rc), } @@ -47,7 +50,7 @@ impl Variable { pub fn serialize_ref(&self) -> RcValue { RefSerializer::new().serialize(self).unwrap() - // self.to_value() + // RcValue::from(self) } pub fn from_object(obj: HashMap, Self>) -> Self { diff --git a/core/types/src/variable/ref_deser.rs b/core/types/src/variable/ref_deser.rs new file mode 100644 index 00000000..1815e64c --- /dev/null +++ b/core/types/src/variable/ref_deser.rs @@ -0,0 +1,313 @@ +use crate::rcvalue::RcValue; +use crate::variable::Variable; +use ahash::{HashMap, HashMapExt}; +use std::cell::RefCell; +use std::rc::Rc; + +pub struct RefDeserializer { + refs: Vec>, +} + +impl RefDeserializer { + pub fn new() -> Self { + Self { refs: Vec::new() } + } + + pub fn deserialize(&mut self, value: RcValue) -> Result { + let RcValue::Object(mut root_obj) = value else { + return Err(DeserializeError::InvalidFormat( + "Expected root object".into(), + )); + }; + + if let Some(RcValue::Array(refs_array)) = root_obj.remove(&Rc::from("$refs")) { + self.refs = vec![None; refs_array.len()]; + + for (i, _) in refs_array.iter().enumerate() { + match &refs_array[i] { + RcValue::Array(_) => { + self.refs[i] = Some(Variable::Array(Rc::new(RefCell::new(Vec::new())))); + } + RcValue::Object(_) => { + self.refs[i] = + Some(Variable::Object(Rc::new(RefCell::new(HashMap::default())))); + } + _ => { + self.refs[i] = Some(self.deserialize_value(&refs_array[i])?); + } + } + } + + for (i, ref_value) in refs_array.iter().enumerate() { + match ref_value { + RcValue::Array(arr) => { + if let Some(Variable::Array(target)) = &self.refs[i] { + let mut items = Vec::with_capacity(arr.len()); + for item in arr { + items.push(self.deserialize_value(item)?); + } + *target.borrow_mut() = items; + } + } + RcValue::Object(obj) => { + if let Some(Variable::Object(target)) = &self.refs[i] { + let mut map = HashMap::with_capacity(obj.len()); + for (key, value) in obj { + let key_var = self.deserialize_key(key)?; + let value_var = self.deserialize_value(value)?; + map.insert(key_var, value_var); + } + *target.borrow_mut() = map; + } + } + _ => {} + } + } + } + + let root_value = root_obj + .remove(&Rc::from("$root")) + .ok_or_else(|| DeserializeError::InvalidFormat("Missing $root".into()))?; + + self.deserialize_value(&root_value) + } + + fn deserialize_key(&self, key: &Rc) -> Result, DeserializeError> { + if let Some(ref_id) = parse_ref_id(key) { + if ref_id >= self.refs.len() { + return Err(DeserializeError::InvalidReference(ref_id)); + } + + match &self.refs[ref_id] { + Some(Variable::String(s)) => Ok(s.clone()), + Some(_) => Err(DeserializeError::InvalidFormat( + "Reference used as key must be a string".into(), + )), + None => Err(DeserializeError::UnresolvedReference(ref_id)), + } + } else { + Ok(unescape_at_string(key)) + } + } + + fn deserialize_value(&self, value: &RcValue) -> Result { + match value { + RcValue::Null => Ok(Variable::Null), + RcValue::Bool(b) => Ok(Variable::Bool(*b)), + RcValue::Number(n) => Ok(Variable::Number(*n)), + RcValue::String(s) => { + if let Some(ref_id) = parse_ref_id(s) { + if ref_id >= self.refs.len() { + return Err(DeserializeError::InvalidReference(ref_id)); + } + + self.refs[ref_id] + .clone() + .ok_or(DeserializeError::UnresolvedReference(ref_id)) + } else { + Ok(Variable::String(unescape_at_string(s))) + } + } + RcValue::Array(arr) => { + let mut items = Vec::with_capacity(arr.len()); + for item in arr { + items.push(self.deserialize_value(item)?); + } + Ok(Variable::Array(Rc::new(RefCell::new(items)))) + } + RcValue::Object(obj) => { + let mut map = HashMap::with_capacity(obj.len()); + for (key, value) in obj { + let key_var = self.deserialize_key(key)?; + let value_var = self.deserialize_value(value)?; + map.insert(key_var, value_var); + } + Ok(Variable::Object(Rc::new(RefCell::new(map)))) + } + } + } +} + +impl Default for RefDeserializer { + fn default() -> Self { + Self::new() + } +} + +#[derive(Debug)] +pub enum DeserializeError { + InvalidFormat(String), + InvalidReference(usize), + UnresolvedReference(usize), +} + +impl std::fmt::Display for DeserializeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DeserializeError::InvalidFormat(msg) => write!(f, "Invalid format: {}", msg), + DeserializeError::InvalidReference(id) => write!(f, "Invalid reference: @{}", id), + DeserializeError::UnresolvedReference(id) => write!(f, "Unresolved reference: @{}", id), + } + } +} + +impl std::error::Error for DeserializeError {} + +fn unescape_at_string(s: &Rc) -> Rc { + if s.starts_with("@@") { + Rc::from(&s[1..]) + } else { + s.clone() + } +} + +fn parse_ref_id(s: &str) -> Option { + s.strip_prefix('@')?.parse().ok() +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::variable::ref_ser::RefSerializer; + use serde_json::json; + + #[test] + fn test_serialize_deserialize_simple() { + let var = Variable::from(json!({ + "name": "Alice", + "age": 30, + "active": true + })); + + let serializer = RefSerializer::new(); + let serialized = serializer.serialize(&var).unwrap(); + + let mut deserializer = RefDeserializer::new(); + let deserialized = deserializer.deserialize(serialized).unwrap(); + + // Should match the original + assert_eq!(var, deserialized); + } + + #[test] + fn test_serialize_deserialize_with_refs() { + let shared_string = "shared_value"; + let var = Variable::from(json!({ + "user1": { + "name": shared_string, + "status": shared_string + }, + "user2": { + "name": shared_string, + "friend": shared_string + }, + "metadata": { + "type": shared_string + } + })); + + let serializer = RefSerializer::new(); + let serialized = serializer.serialize(&var).unwrap(); + + // Check that refs were created + if let RcValue::Object(ref obj) = serialized { + assert!(obj.contains_key(&Rc::from("$refs"))); + assert!(obj.contains_key(&Rc::from("$root"))); + } else { + panic!("Expected object"); + } + + let mut deserializer = RefDeserializer::new(); + let deserialized = deserializer.deserialize(serialized).unwrap(); + + assert_eq!(var, deserialized); + } + + #[test] + fn test_serialize_deserialize_array_refs() { + let shared_array = vec![1, 2, 3]; + let var = Variable::from(json!({ + "data1": shared_array, + "data2": shared_array, + "backup": shared_array + })); + + let serializer = RefSerializer::new(); + let serialized = serializer.serialize(&var).unwrap(); + + let mut deserializer = RefDeserializer::new(); + let deserialized = deserializer.deserialize(serialized).unwrap(); + + assert_eq!(var, deserialized); + } + + #[test] + fn test_serialize_deserialize_at_string_escaping() { + let var = Variable::from(json!({ + "normal": "hello", + "at_string": "@special", + "double_at": "@@escaped" + })); + + let serializer = RefSerializer::new(); + let serialized = serializer.serialize(&var).unwrap(); + + let mut deserializer = RefDeserializer::new(); + let deserialized = deserializer.deserialize(serialized).unwrap(); + + assert_eq!(var, deserialized); + } + + #[test] + fn test_serialize_deserialize_nested_structure() { + let var = Variable::from(json!({ + "level1": { + "level2": { + "level3": { + "data": "deep_value", + "numbers": [1, 2, 3, 4, 5] + } + }, + "shared": "common_string" + }, + "other": { + "ref": "common_string" + }, + "array": [ + {"shared": "common_string"}, + {"different": "unique"} + ] + })); + + let serializer = RefSerializer::new(); + let serialized = serializer.serialize(&var).unwrap(); + + let mut deserializer = RefDeserializer::new(); + let deserialized = deserializer.deserialize(serialized).unwrap(); + + assert_eq!(var, deserialized); + } + + #[test] + fn test_no_refs_when_below_threshold() { + // String too short, should not create refs + let var = Variable::from(json!({ + "a": "hi", + "b": "hi", + "c": "hi" + })); + + let serializer = RefSerializer::new(); + let serialized = serializer.serialize(&var).unwrap(); + + // Should not have refs section + if let RcValue::Object(ref obj) = serialized { + assert!(!obj.contains_key(&Rc::from("$refs"))); + } + + let mut deserializer = RefDeserializer::new(); + let deserialized = deserializer.deserialize(serialized).unwrap(); + + assert_eq!(var, deserialized); + } +} diff --git a/core/types/src/variable_type/mod.rs b/core/types/src/variable_type/mod.rs index bdf0c446..6a96ff0b 100644 --- a/core/types/src/variable_type/mod.rs +++ b/core/types/src/variable_type/mod.rs @@ -2,6 +2,7 @@ mod conv; mod util; use crate::variable::RcCell; +pub use ahash::HashMapExt as VariableMapExt; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fmt::{Display, Write}; From 812a9cefef32b920ce4c4f43a84336fcfa2bd4e7 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 18 Aug 2025 14:44:37 +0200 Subject: [PATCH 04/14] add tests and deserializer --- .../src/intellisense/types/provider.rs | 2 +- core/types/Cargo.toml | 1 + core/types/src/variable/mod.rs | 9 +- core/types/src/variable/ref_deser.rs | 193 +----------- core/types/src/variable/ref_ser.rs | 34 +-- core/types/src/variable_type/conv.rs | 14 - core/types/src/variable_type/mod.rs | 2 +- core/types/src/variable_type/util.rs | 49 +-- core/types/tests/ref_ser.rs | 260 ++++++++++++++++ core/types/tests/variable.rs | 206 +++++++++++++ core/types/tests/variable_type.rs | 278 ++++++++++++++++++ 11 files changed, 785 insertions(+), 263 deletions(-) create mode 100644 core/types/tests/ref_ser.rs create mode 100644 core/types/tests/variable.rs create mode 100644 core/types/tests/variable_type.rs diff --git a/core/expression/src/intellisense/types/provider.rs b/core/expression/src/intellisense/types/provider.rs index 1c8c6a0e..454eedfb 100644 --- a/core/expression/src/intellisense/types/provider.rs +++ b/core/expression/src/intellisense/types/provider.rs @@ -5,8 +5,8 @@ use crate::intellisense::types::type_info::TypeInfo; use crate::lexer::{ArithmeticOperator, ComparisonOperator, LogicalOperator, Operator}; use crate::parser::Node; use crate::variable::VariableType; +use ahash::{HashMap, HashMapExt}; use std::cell::RefCell; -use std::collections::HashMap; use std::iter::once; use std::ops::Deref; use std::rc::Rc; diff --git a/core/types/Cargo.toml b/core/types/Cargo.toml index a15a6131..dcd3047b 100644 --- a/core/types/Cargo.toml +++ b/core/types/Cargo.toml @@ -10,4 +10,5 @@ serde = { workspace = true, features = ["rc", "derive"] } serde_json = { workspace = true, features = ["arbitrary_precision"] } rust_decimal = { workspace = true, features = ["maths-nopanic"] } rust_decimal_macros = { workspace = true } +thiserror = { workspace = true } nohash-hasher = "0.2.0" diff --git a/core/types/src/variable/mod.rs b/core/types/src/variable/mod.rs index 8da8a435..644d6f8f 100644 --- a/core/types/src/variable/mod.rs +++ b/core/types/src/variable/mod.rs @@ -11,6 +11,8 @@ use std::ops::Deref; use std::rc::Rc; use crate::rcvalue::RcValue; +pub use crate::variable::ref_deser::RefDeserializeError; +use crate::variable::ref_deser::RefDeserializer; pub use de::VariableDeserializer; pub use impls::ToVariable; @@ -49,8 +51,11 @@ impl Variable { } pub fn serialize_ref(&self) -> RcValue { - RefSerializer::new().serialize(self).unwrap() - // RcValue::from(self) + RefSerializer::new().serialize(self) + } + + pub fn deserialize_ref(serialized: RcValue) -> Result { + RefDeserializer::new().deserialize(serialized) } pub fn from_object(obj: HashMap, Self>) -> Self { diff --git a/core/types/src/variable/ref_deser.rs b/core/types/src/variable/ref_deser.rs index 1815e64c..d3762141 100644 --- a/core/types/src/variable/ref_deser.rs +++ b/core/types/src/variable/ref_deser.rs @@ -3,6 +3,7 @@ use crate::variable::Variable; use ahash::{HashMap, HashMapExt}; use std::cell::RefCell; use std::rc::Rc; +use thiserror::Error; pub struct RefDeserializer { refs: Vec>, @@ -13,9 +14,9 @@ impl RefDeserializer { Self { refs: Vec::new() } } - pub fn deserialize(&mut self, value: RcValue) -> Result { + pub fn deserialize(&mut self, value: RcValue) -> Result { let RcValue::Object(mut root_obj) = value else { - return Err(DeserializeError::InvalidFormat( + return Err(RefDeserializeError::InvalidFormat( "Expected root object".into(), )); }; @@ -67,30 +68,30 @@ impl RefDeserializer { let root_value = root_obj .remove(&Rc::from("$root")) - .ok_or_else(|| DeserializeError::InvalidFormat("Missing $root".into()))?; + .ok_or_else(|| RefDeserializeError::InvalidFormat("Missing $root".into()))?; self.deserialize_value(&root_value) } - fn deserialize_key(&self, key: &Rc) -> Result, DeserializeError> { + fn deserialize_key(&self, key: &Rc) -> Result, RefDeserializeError> { if let Some(ref_id) = parse_ref_id(key) { if ref_id >= self.refs.len() { - return Err(DeserializeError::InvalidReference(ref_id)); + return Err(RefDeserializeError::InvalidReference(ref_id)); } match &self.refs[ref_id] { Some(Variable::String(s)) => Ok(s.clone()), - Some(_) => Err(DeserializeError::InvalidFormat( + Some(_) => Err(RefDeserializeError::InvalidFormat( "Reference used as key must be a string".into(), )), - None => Err(DeserializeError::UnresolvedReference(ref_id)), + None => Err(RefDeserializeError::UnresolvedReference(ref_id)), } } else { Ok(unescape_at_string(key)) } } - fn deserialize_value(&self, value: &RcValue) -> Result { + fn deserialize_value(&self, value: &RcValue) -> Result { match value { RcValue::Null => Ok(Variable::Null), RcValue::Bool(b) => Ok(Variable::Bool(*b)), @@ -98,12 +99,12 @@ impl RefDeserializer { RcValue::String(s) => { if let Some(ref_id) = parse_ref_id(s) { if ref_id >= self.refs.len() { - return Err(DeserializeError::InvalidReference(ref_id)); + return Err(RefDeserializeError::InvalidReference(ref_id)); } self.refs[ref_id] .clone() - .ok_or(DeserializeError::UnresolvedReference(ref_id)) + .ok_or(RefDeserializeError::UnresolvedReference(ref_id)) } else { Ok(Variable::String(unescape_at_string(s))) } @@ -128,31 +129,16 @@ impl RefDeserializer { } } -impl Default for RefDeserializer { - fn default() -> Self { - Self::new() - } -} - -#[derive(Debug)] -pub enum DeserializeError { +#[derive(Debug, Error)] +pub enum RefDeserializeError { + #[error("Invalid format: {0}")] InvalidFormat(String), + #[error("Invalid reference: {0}")] InvalidReference(usize), + #[error("UnresolvedReference: {0}")] UnresolvedReference(usize), } -impl std::fmt::Display for DeserializeError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - DeserializeError::InvalidFormat(msg) => write!(f, "Invalid format: {}", msg), - DeserializeError::InvalidReference(id) => write!(f, "Invalid reference: @{}", id), - DeserializeError::UnresolvedReference(id) => write!(f, "Unresolved reference: @{}", id), - } - } -} - -impl std::error::Error for DeserializeError {} - fn unescape_at_string(s: &Rc) -> Rc { if s.starts_with("@@") { Rc::from(&s[1..]) @@ -164,150 +150,3 @@ fn unescape_at_string(s: &Rc) -> Rc { fn parse_ref_id(s: &str) -> Option { s.strip_prefix('@')?.parse().ok() } - -#[cfg(test)] -mod tests { - use super::*; - use crate::variable::ref_ser::RefSerializer; - use serde_json::json; - - #[test] - fn test_serialize_deserialize_simple() { - let var = Variable::from(json!({ - "name": "Alice", - "age": 30, - "active": true - })); - - let serializer = RefSerializer::new(); - let serialized = serializer.serialize(&var).unwrap(); - - let mut deserializer = RefDeserializer::new(); - let deserialized = deserializer.deserialize(serialized).unwrap(); - - // Should match the original - assert_eq!(var, deserialized); - } - - #[test] - fn test_serialize_deserialize_with_refs() { - let shared_string = "shared_value"; - let var = Variable::from(json!({ - "user1": { - "name": shared_string, - "status": shared_string - }, - "user2": { - "name": shared_string, - "friend": shared_string - }, - "metadata": { - "type": shared_string - } - })); - - let serializer = RefSerializer::new(); - let serialized = serializer.serialize(&var).unwrap(); - - // Check that refs were created - if let RcValue::Object(ref obj) = serialized { - assert!(obj.contains_key(&Rc::from("$refs"))); - assert!(obj.contains_key(&Rc::from("$root"))); - } else { - panic!("Expected object"); - } - - let mut deserializer = RefDeserializer::new(); - let deserialized = deserializer.deserialize(serialized).unwrap(); - - assert_eq!(var, deserialized); - } - - #[test] - fn test_serialize_deserialize_array_refs() { - let shared_array = vec![1, 2, 3]; - let var = Variable::from(json!({ - "data1": shared_array, - "data2": shared_array, - "backup": shared_array - })); - - let serializer = RefSerializer::new(); - let serialized = serializer.serialize(&var).unwrap(); - - let mut deserializer = RefDeserializer::new(); - let deserialized = deserializer.deserialize(serialized).unwrap(); - - assert_eq!(var, deserialized); - } - - #[test] - fn test_serialize_deserialize_at_string_escaping() { - let var = Variable::from(json!({ - "normal": "hello", - "at_string": "@special", - "double_at": "@@escaped" - })); - - let serializer = RefSerializer::new(); - let serialized = serializer.serialize(&var).unwrap(); - - let mut deserializer = RefDeserializer::new(); - let deserialized = deserializer.deserialize(serialized).unwrap(); - - assert_eq!(var, deserialized); - } - - #[test] - fn test_serialize_deserialize_nested_structure() { - let var = Variable::from(json!({ - "level1": { - "level2": { - "level3": { - "data": "deep_value", - "numbers": [1, 2, 3, 4, 5] - } - }, - "shared": "common_string" - }, - "other": { - "ref": "common_string" - }, - "array": [ - {"shared": "common_string"}, - {"different": "unique"} - ] - })); - - let serializer = RefSerializer::new(); - let serialized = serializer.serialize(&var).unwrap(); - - let mut deserializer = RefDeserializer::new(); - let deserialized = deserializer.deserialize(serialized).unwrap(); - - assert_eq!(var, deserialized); - } - - #[test] - fn test_no_refs_when_below_threshold() { - // String too short, should not create refs - let var = Variable::from(json!({ - "a": "hi", - "b": "hi", - "c": "hi" - })); - - let serializer = RefSerializer::new(); - let serialized = serializer.serialize(&var).unwrap(); - - // Should not have refs section - if let RcValue::Object(ref obj) = serialized { - assert!(!obj.contains_key(&Rc::from("$refs"))); - } - - let mut deserializer = RefDeserializer::new(); - let deserialized = deserializer.deserialize(serialized).unwrap(); - - assert_eq!(var, deserialized); - } -} diff --git a/core/types/src/variable/ref_ser.rs b/core/types/src/variable/ref_ser.rs index f261c5e0..047e3d07 100644 --- a/core/types/src/variable/ref_ser.rs +++ b/core/types/src/variable/ref_ser.rs @@ -47,11 +47,11 @@ impl RefSerializer { Rc::as_ptr(&reference) as *const () as usize } - pub fn serialize(mut self, var: &Variable) -> serde_json::Result { + pub fn serialize(mut self, var: &Variable) -> RcValue { self.count_refs(var); self.assign_ref_ids(); - let data = self.serialize_with_refs(var)?; + let data = self.serialize_with_refs(var); let mut result = HashMap::default(); if !self.ref_data.is_empty() { @@ -59,7 +59,7 @@ impl RefSerializer { } result.insert(Rc::from("$root"), data); - Ok(RcValue::Object(result)) + RcValue::Object(result) } fn count_refs(&mut self, var: &Variable) { @@ -118,42 +118,42 @@ impl RefSerializer { } } - fn serialize_with_refs(&mut self, var: &Variable) -> serde_json::Result { + fn serialize_with_refs(&mut self, var: &Variable) -> RcValue { match var { Variable::String(s) => { let addr = self.intern_string_addr(s); let Some((id, id_str)) = self.refs.get(&addr) else { - return Ok(RcValue::String(Self::escape_at_string(s))); + return RcValue::String(Self::escape_at_string(s)); }; if self.ref_data[*id] == RcValue::Null { self.ref_data[*id] = RcValue::String(Self::escape_at_string(s)); } - Ok(RcValue::String(id_str.clone())) + RcValue::String(id_str.clone()) } Variable::Array(arr) => { let addr = Rc::as_ptr(arr) as *const () as usize; let data = { let borrowed = arr.borrow(); - let items: Result, _> = borrowed + let items: Vec<_> = borrowed .iter() .map(|item| self.serialize_with_refs(item)) .collect(); - RcValue::Array(items?) + RcValue::Array(items) }; let Some((id, id_str)) = self.refs.get(&addr) else { - return Ok(data); + return data; }; if self.ref_data[*id] == RcValue::Null { self.ref_data[*id] = data; } - Ok(RcValue::String(id_str.clone())) + RcValue::String(id_str.clone()) } Variable::Object(obj) => { @@ -178,30 +178,24 @@ impl RefSerializer { Self::escape_at_string(key) }; - map.insert(key_str, self.serialize_with_refs(value)?); + map.insert(key_str, self.serialize_with_refs(value)); } RcValue::Object(map) }; let Some((id, id_str)) = self.refs.get(&addr) else { - return Ok(data); + return data; }; if self.ref_data[*id] == RcValue::Null { self.ref_data[*id] = data; } - Ok(RcValue::String(id_str.clone())) + RcValue::String(id_str.clone()) } - _ => Ok(RcValue::from(var)), + _ => RcValue::from(var), } } } - -impl Default for RefSerializer { - fn default() -> Self { - Self::new() - } -} diff --git a/core/types/src/variable_type/conv.rs b/core/types/src/variable_type/conv.rs index 67be7e3f..943b5bda 100644 --- a/core/types/src/variable_type/conv.rs +++ b/core/types/src/variable_type/conv.rs @@ -79,17 +79,3 @@ impl From<&Vec> for VariableType { VariableType::Array(Rc::new(result_type.unwrap_or(VariableType::Any))) } } - -#[cfg(test)] -mod tests { - use super::*; - use serde_json::json; - - #[test] - fn test_value_to_value_kind() { - assert_eq!(VariableType::from(json!(null)), VariableType::Null); - assert_eq!(VariableType::from(json!(true)), VariableType::Bool); - assert_eq!(VariableType::from(json!(42)), VariableType::Number); - assert_eq!(VariableType::from(json!("hello")), VariableType::String); - } -} diff --git a/core/types/src/variable_type/mod.rs b/core/types/src/variable_type/mod.rs index 6a96ff0b..dabcf776 100644 --- a/core/types/src/variable_type/mod.rs +++ b/core/types/src/variable_type/mod.rs @@ -2,9 +2,9 @@ mod conv; mod util; use crate::variable::RcCell; +use ahash::HashMap; pub use ahash::HashMapExt as VariableMapExt; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; use std::fmt::{Display, Write}; use std::hash::{Hash, Hasher}; use std::rc::Rc; diff --git a/core/types/src/variable_type/util.rs b/core/types/src/variable_type/util.rs index 3909edb1..03e17d18 100644 --- a/core/types/src/variable_type/util.rs +++ b/core/types/src/variable_type/util.rs @@ -1,7 +1,7 @@ use crate::variable_type::VariableType; +use ahash::{HashMap, HashMapExt}; use rust_decimal::prelude::Zero; use std::cell::RefCell; -use std::collections::HashMap; use std::collections::hash_map::Entry; use std::rc::Rc; @@ -320,50 +320,3 @@ impl VariableType { }) } } - -#[cfg(test)] -mod tests { - use crate::variable_type::VariableType; - use std::rc::Rc; - - #[test] - fn merge_simple() { - assert_eq!( - VariableType::Number.merge(&VariableType::Number), - VariableType::Number - ); - assert_eq!( - VariableType::String.merge(&VariableType::String), - VariableType::String - ); - assert_eq!( - VariableType::Bool.merge(&VariableType::Bool), - VariableType::Bool - ); - assert_eq!( - VariableType::Null.merge(&VariableType::Null), - VariableType::Null - ); - assert_eq!( - VariableType::Any.merge(&VariableType::Any), - VariableType::Any - ); - } - - #[test] - fn merge_array() { - assert_eq!( - VariableType::Array(Rc::new(VariableType::Number)) - .merge(&VariableType::Array(Rc::new(VariableType::Number))), - VariableType::Array(Rc::new(VariableType::Number)) - ); - } - - #[test] - fn merge_mixed() { - assert_eq!( - VariableType::Number.merge(&VariableType::String), - VariableType::Any - ); - } -} diff --git a/core/types/tests/ref_ser.rs b/core/types/tests/ref_ser.rs new file mode 100644 index 00000000..5a6e02d8 --- /dev/null +++ b/core/types/tests/ref_ser.rs @@ -0,0 +1,260 @@ +use ahash::{HashMap, HashMapExt}; +use rust_decimal_macros::dec; +use serde_json::json; +use std::cell::RefCell; +use std::error::Error; +use std::rc::Rc; +use zen_types::rcvalue::RcValue; +use zen_types::variable::Variable; + +type TestResult = Result<(), Box>; + +#[test] +fn serialize_deserialize_simple() -> TestResult { + let var = Variable::from(json!({ + "name": "Alice", + "age": 30, + "active": true + })); + + let serialized = var.serialize_ref(); + let deserialized = Variable::deserialize_ref(serialized)?; + + assert_eq!(var, deserialized); + + Ok(()) +} + +#[test] +fn serialize_deserialize_with_refs() -> TestResult { + let shared_string = "shared_value"; + let var = Variable::from(json!({ + "user1": { + "name": shared_string, + "status": shared_string + }, + "user2": { + "name": shared_string, + "friend": shared_string + }, + "metadata": { + "type": shared_string + } + })); + + let serialized = var.serialize_ref(); + + // Check that refs were created + if let RcValue::Object(ref obj) = serialized { + assert!(obj.contains_key(&Rc::from("$refs"))); + assert!(obj.contains_key(&Rc::from("$root"))); + } else { + panic!("Expected object"); + } + + let deserialized = Variable::deserialize_ref(serialized)?; + assert_eq!(var, deserialized); + + Ok(()) +} + +#[test] +fn serialize_deserialize_array_refs() -> TestResult { + let shared_array = vec![1, 2, 3]; + let var = Variable::from(json!({ + "data1": shared_array, + "data2": shared_array, + "backup": shared_array + })); + + let serialized = var.serialize_ref(); + let deserialized = Variable::deserialize_ref(serialized)?; + + assert_eq!(var, deserialized); + + Ok(()) +} + +#[test] +fn serialize_deserialize_at_string_escaping() -> TestResult { + let var = Variable::from(json!({ + "normal": "hello", + "at_string": "@special", + "double_at": "@@escaped" + })); + + let serialized = var.serialize_ref(); + let deserialized = Variable::deserialize_ref(serialized)?; + + assert_eq!(var, deserialized); + + Ok(()) +} + +#[test] +fn serialize_deserialize_nested_structure() -> TestResult { + let var = Variable::from(json!({ + "level1": { + "level2": { + "level3": { + "data": "deep_value", + "numbers": [1, 2, 3, 4, 5] + } + }, + "shared": "common_string" + }, + "other": { + "ref": "common_string" + }, + "array": [ + {"shared": "common_string"}, + {"different": "unique"} + ] + })); + + let serialized = var.serialize_ref(); + let deserialized = Variable::deserialize_ref(serialized)?; + + assert_eq!(var, deserialized); + + Ok(()) +} + +#[test] +fn no_refs_when_below_threshold() -> TestResult { + // String too short, should not create refs + let var = Variable::from(json!({ + "a": "hi", + "b": "hi", + "c": "hi" + })); + + let serialized = var.serialize_ref(); + + // Should not have refs section + if let RcValue::Object(ref obj) = serialized { + assert!(!obj.contains_key(&Rc::from("$refs"))); + } + + let deserialized = Variable::deserialize_ref(serialized)?; + assert_eq!(var, deserialized); + + Ok(()) +} + +#[test] +fn serialize_circular_references() -> TestResult { + // Create a shared object that will be referenced multiple times + let shared_obj = Rc::new(RefCell::new({ + let mut map = HashMap::new(); + map.insert( + Rc::from("shared_data"), + Variable::String(Rc::from("important_value")), + ); + map.insert(Rc::from("id"), Variable::Number(dec!(42.0))); + map + })); + + // Create a structure where the same object appears in multiple places + let mut root_map = HashMap::new(); + root_map.insert(Rc::from("first_ref"), Variable::Object(shared_obj.clone())); + root_map.insert(Rc::from("second_ref"), Variable::Object(shared_obj.clone())); + root_map.insert(Rc::from("third_ref"), Variable::Object(shared_obj)); + + let var = Variable::Object(Rc::new(RefCell::new(root_map))); + + let serialized = var.serialize_ref(); + let deserialized = Variable::deserialize_ref(serialized)?; + + assert_eq!(var, deserialized); + + Ok(()) +} + +#[test] +fn serialize_same_array_multiple_locations() -> TestResult { + use std::cell::RefCell; + + // Create a shared array + let shared_array = Rc::new(RefCell::new(vec![ + Variable::String(Rc::from("item_one")), + Variable::String(Rc::from("item_two")), + Variable::Number(dec!(123.0)), + ])); + + let var = Variable::from(json!({ + "list1": shared_array.clone(), + "backup_list": shared_array.clone(), + "nested": { + "inner_list": shared_array + } + })); + + let serialized = var.serialize_ref(); + let deserialized = Variable::deserialize_ref(serialized)?; + + assert_eq!(var, deserialized); + + Ok(()) +} + +#[test] +fn serialize_mixed_shared_references() -> TestResult { + let shared_string: Rc = Rc::from("shared_between_key_and_value"); + + // Create an object where the same string is used as both key and value + let mut obj_map = HashMap::new(); + obj_map.insert( + shared_string.clone(), + Variable::String(shared_string.clone()), + ); + obj_map.insert( + Rc::from("other_key"), + Variable::String(shared_string.clone()), + ); + + let shared_obj = Rc::new(RefCell::new(obj_map)); + + // Use the shared object in multiple places + let var = Variable::from(json!({ + "container1": shared_obj.clone(), + "container2": shared_obj.clone(), + "metadata": { + "reference": shared_obj + } + })); + + let serialized = var.serialize_ref(); + let deserialized = Variable::deserialize_ref(serialized)?; + + assert_eq!(var, deserialized); + + Ok(()) +} + +#[test] +fn serialize_shared_array_with_shared_strings() -> TestResult { + let shared_string: Rc = Rc::from("shared_string_value"); + + // Create a shared array containing the shared string + let shared_array = Rc::new(RefCell::new(vec![ + Variable::String(shared_string.clone()), + Variable::Number(dec!(42.0)), + Variable::String(shared_string.clone()), + ])); + + // Use the shared array in multiple places + let mut root_map = HashMap::new(); + root_map.insert(Rc::from("array1"), Variable::Array(shared_array.clone())); + root_map.insert(Rc::from("array2"), Variable::Array(shared_array.clone())); + root_map.insert(Rc::from("array3"), Variable::Array(shared_array)); + + let var = Variable::Object(Rc::new(RefCell::new(root_map))); + + let serialized = var.serialize_ref(); + let deserialized = Variable::deserialize_ref(serialized)?; + + assert_eq!(var, deserialized); + + Ok(()) +} diff --git a/core/types/tests/variable.rs b/core/types/tests/variable.rs new file mode 100644 index 00000000..5715989c --- /dev/null +++ b/core/types/tests/variable.rs @@ -0,0 +1,206 @@ +use rust_decimal_macros::dec; +use serde_json::json; +use std::error::Error; +use std::rc::Rc; +use zen_types::variable::Variable; + +type TestResult = Result<(), Box>; +#[test] +fn dot_operations() -> TestResult { + let var = Variable::from(json!({ + "user": { + "profile": { + "name": "Alice", + "age": 30 + } + } + })); + + // Test dot get + assert_eq!( + var.dot("user.profile.name"), + Some(Variable::String(Rc::from("Alice"))) + ); + assert_eq!(var.dot("user.profile.nonexistent"), None); + assert_eq!(var.dot("nonexistent.path"), None); + + // Test dot insert + let updated = var.dot_insert( + "user.profile.email", + Variable::String(Rc::from("alice@example.com")), + ); + assert!(updated.is_none()); // Returns previous value (none) + assert_eq!( + var.dot("user.profile.email"), + Some(Variable::String(Rc::from("alice@example.com"))) + ); + + // Test dot insert detached + let new_var = var + .dot_insert_detached("settings.theme", Variable::String(Rc::from("dark"))) + .ok_or_else(|| "Failed to insert detached path".to_string())?; + assert_eq!( + new_var.dot("settings.theme"), + Some(Variable::String(Rc::from("dark"))) + ); + assert_eq!(var.dot("settings.theme"), None); // Original unchanged + + // Test dot remove + let removed = var.dot_remove("user.profile.age"); + assert_eq!(removed, Some(Variable::Number(dec!(30)))); + assert_eq!(var.dot("user.profile.age"), None); + + Ok(()) +} + +#[test] +fn clone_operations() -> TestResult { + let original = Variable::from(json!({ + "data": [1, 2, {"nested": "value"}], + "count": 42 + })); + + // Test shallow clone - shares references + let shallow = original.shallow_clone(); + if let (Variable::Array(orig_arr), Variable::Array(shallow_arr)) = (&original, &shallow) { + assert!(Rc::ptr_eq(orig_arr, shallow_arr)); + } + + // Test depth clone + let depth1 = original.depth_clone(1); + if let (Variable::Array(orig_arr), Variable::Array(depth_arr)) = (&original, &depth1) { + assert!(!Rc::ptr_eq(orig_arr, depth_arr)); // Different array refs + + let orig_nested = &orig_arr.borrow()[2]; + let depth_nested = &depth_arr.borrow()[2]; + if let (Variable::Object(orig_obj), Variable::Object(depth_obj)) = + (orig_nested, depth_nested) + { + assert!(Rc::ptr_eq(orig_obj, depth_obj)); // Nested still shared at depth 1 + } + } + + // Test deep clone - everything separate + let deep = original.deep_clone(); + if let (Variable::Array(orig_arr), Variable::Array(deep_arr)) = (&original, &deep) { + assert!(!Rc::ptr_eq(orig_arr, deep_arr)); + + let orig_nested = &orig_arr.borrow()[2]; + let deep_nested = &deep_arr.borrow()[2]; + if let (Variable::Object(orig_obj), Variable::Object(deep_obj)) = (orig_nested, deep_nested) + { + assert!(!Rc::ptr_eq(orig_obj, deep_obj)); // Nested also separate + } + } + + Ok(()) +} + +#[test] +fn merge_operations() -> TestResult { + let mut doc = Variable::from(json!({ + "user": {"name": "Alice", "age": 30}, + "settings": {"theme": "light"} + })); + + let patch = Variable::from(json!({ + "user": {"age": 31, "email": "alice@example.com"}, + "settings": {"notifications": true}, + "new_field": "value" + })); + + // Test merge clone (doesn't modify original) + let merged = doc.merge_clone(&patch); + assert_eq!(doc.dot("user.age"), Some(Variable::Number(dec!(30)))); // Original unchanged + assert_eq!(merged.dot("user.age"), Some(Variable::Number(dec!(31)))); // Merged updated + assert_eq!( + merged.dot("user.email"), + Some(Variable::String(Rc::from("alice@example.com"))) + ); + assert_eq!( + merged.dot("new_field"), + Some(Variable::String(Rc::from("value"))) + ); + + // Test in-place merge + doc.merge(&patch); + assert_eq!(doc.dot("user.age"), Some(Variable::Number(dec!(31)))); // Original now changed + assert_eq!( + doc.dot("user.name"), + Some(Variable::String(Rc::from("Alice"))) + ); // Preserved + assert_eq!( + doc.dot("settings.notifications"), + Some(Variable::Bool(true)) + ); // Added + + // Test null removal + let null_patch = Variable::from(json!({"user": {"name": null}})); + doc.merge(&null_patch); + assert_eq!(doc.dot("user.name"), None); // Removed by null + + Ok(()) +} + +#[test] +fn type_operations() -> TestResult { + let var = Variable::from(json!({ + "string": "hello", + "number": 42, + "bool": true, + "array": [1, 2, 3], + "object": {"key": "value"}, + "null": null + })); + + // Test type checks + assert!(var.dot("array").unwrap().is_array()); + assert!(var.dot("object").unwrap().is_object()); + assert!(!var.dot("string").unwrap().is_array()); + + // Test accessors + assert_eq!(var.dot("string").unwrap().as_str(), Some("hello")); + assert_eq!(var.dot("number").unwrap().as_number(), Some(dec!(42))); + assert_eq!(var.dot("bool").unwrap().as_bool(), Some(true)); + assert!(var.dot("array").unwrap().as_array().is_some()); + assert!(var.dot("object").unwrap().as_object().is_some()); + + // Test type names + assert_eq!(var.dot("string").unwrap().type_name(), "string"); + assert_eq!(var.dot("number").unwrap().type_name(), "number"); + assert_eq!(var.dot("bool").unwrap().type_name(), "bool"); + assert_eq!(var.dot("array").unwrap().type_name(), "array"); + assert_eq!(var.dot("object").unwrap().type_name(), "object"); + assert_eq!(var.dot("null").unwrap().type_name(), "null"); + + Ok(()) +} + +#[test] +fn edge_cases() -> TestResult { + // Empty structures + let empty_obj = Variable::empty_object(); + let empty_arr = Variable::empty_array(); + assert!(empty_obj.is_object()); + assert!(empty_arr.is_array()); + + // Dot operations on non-objects + let number = Variable::Number(dec!(42)); + assert_eq!(number.dot("anything"), None); + assert_eq!(number.dot_insert("path", Variable::Null), None); + assert_eq!(number.dot_remove("path"), None); + + // Array merge at top level + let mut doc = Variable::from(json!({"key": "value"})); + let array_patch = Variable::from(json!([1, 2, 3])); + doc.merge(&array_patch); + assert!(doc.is_array()); // Replaced with array + + // Self-merge (no-op) + let mut original = Variable::from(json!({"a": 1})); + let clone = original.shallow_clone(); + original.merge(&clone); + assert_eq!(original.dot("a"), Some(Variable::Number(dec!(1)))); + + Ok(()) +} diff --git a/core/types/tests/variable_type.rs b/core/types/tests/variable_type.rs new file mode 100644 index 00000000..f9819194 --- /dev/null +++ b/core/types/tests/variable_type.rs @@ -0,0 +1,278 @@ +use ahash::{HashMap, HashMapExt}; +use serde_json::json; +use std::cell::RefCell; +use std::rc::Rc; +use zen_types::variable_type::VariableType; + +type TestResult = Result<(), Box>; + +#[test] +fn variable_type_operations() -> TestResult { + // Test basic types and accessors + assert!(VariableType::Array(Rc::new(VariableType::Number)).is_array()); + assert!(VariableType::Interval.is_iterable()); + assert!(VariableType::String.is_string()); + assert!(VariableType::empty_object().is_object()); + assert!(VariableType::Null.is_null()); + + // Test iterator + assert_eq!( + VariableType::Array(Rc::new(VariableType::String)).iterator(), + Some(Rc::new(VariableType::String)) + ); + assert_eq!( + VariableType::Interval.iterator(), + Some(Rc::new(VariableType::Number)) + ); + assert_eq!(VariableType::String.iterator(), None); + + // Test const string extraction + let const_type = VariableType::Const(Rc::from("test")); + assert_eq!(const_type.as_const_str(), Some(Rc::from("test"))); + assert_eq!(VariableType::String.as_const_str(), None); + + // Test widen + assert_eq!(const_type.widen(), VariableType::String); + assert_eq!( + VariableType::Enum(None, vec![Rc::from("a")]).widen(), + VariableType::String + ); + assert_eq!(VariableType::Number.widen(), VariableType::Number); + + Ok(()) +} + +#[test] +fn variable_type_satisfies() -> TestResult { + // Basic type satisfaction + assert!(VariableType::Any.satisfies(&VariableType::String)); + assert!(VariableType::String.satisfies(&VariableType::Any)); + assert!(VariableType::Number.satisfies(&VariableType::Number)); + assert!(!VariableType::String.satisfies(&VariableType::Number)); + + // Date satisfaction + assert!(VariableType::Number.satisfies(&VariableType::Date)); + assert!(VariableType::String.satisfies(&VariableType::Date)); + + // Const and enum satisfaction + let const_a = VariableType::Const(Rc::from("a")); + let enum_ab = VariableType::Enum(None, vec![Rc::from("a"), Rc::from("b")]); + assert!(const_a.satisfies(&VariableType::String)); + assert!(const_a.satisfies(&enum_ab)); + assert!(enum_ab.satisfies(&VariableType::String)); + + // Array satisfaction + let arr_num = VariableType::Array(Rc::new(VariableType::Number)); + let arr_str = VariableType::Array(Rc::new(VariableType::String)); + assert!(arr_num.satisfies(&arr_num)); + assert!(!arr_num.satisfies(&arr_str)); + + Ok(()) +} + +#[test] +fn variable_type_merge() -> TestResult { + // Basic merges + assert_eq!( + VariableType::Number.merge(&VariableType::String), + VariableType::Any + ); + assert_eq!( + VariableType::String.merge(&VariableType::String), + VariableType::String + ); + assert_eq!( + VariableType::Date.merge(&VariableType::Date), + VariableType::Date + ); + assert_eq!( + VariableType::Interval.merge(&VariableType::Interval), + VariableType::Interval + ); + + // Const merges + let const_a = VariableType::Const(Rc::from("a")); + let const_b = VariableType::Const(Rc::from("b")); + let merged = const_a.merge(&const_b); + assert!(matches!(merged, VariableType::Enum(None, _))); + + // Same const merge + assert_eq!(const_a.merge(&const_a), const_a); + + // Const with string + assert_eq!(const_a.merge(&VariableType::String), VariableType::String); + + // Const with enum and enum with const + let enum_bc = VariableType::Enum(None, vec![Rc::from("b"), Rc::from("c")]); + let const_enum_merge = const_a.merge(&enum_bc); + if let VariableType::Enum(_, vals) = const_enum_merge { + assert_eq!(vals.len(), 3); + } + + let enum_const_merge = enum_bc.merge(&const_a); + if let VariableType::Enum(_, vals) = enum_const_merge { + assert_eq!(vals.len(), 3); + } + + // Array merge with same pointer + let shared_array_type = Rc::new(VariableType::Number); + let arr1 = VariableType::Array(shared_array_type.clone()); + let arr2 = VariableType::Array(shared_array_type); + assert_eq!(arr1.merge(&arr2), arr1); + + // Object merge + let obj1 = VariableType::Object(Rc::new(RefCell::new({ + let mut map = HashMap::new(); + map.insert(Rc::from("key1"), VariableType::String); + map.insert(Rc::from("shared"), VariableType::Number); + map + }))); + let obj2 = VariableType::Object(Rc::new(RefCell::new({ + let mut map = HashMap::new(); + map.insert(Rc::from("key2"), VariableType::Bool); + map.insert(Rc::from("shared"), VariableType::String); + map + }))); + let merged_obj = obj1.merge(&obj2); + if let VariableType::Object(obj_ref) = merged_obj { + let obj_map = obj_ref.borrow(); + assert_eq!(obj_map.len(), 3); + assert_eq!(obj_map.get("shared"), Some(&VariableType::Any)); + } + + // Enum merges + let enum1 = VariableType::Enum(Some(Rc::from("E1")), vec![Rc::from("x")]); + let enum2 = VariableType::Enum(Some(Rc::from("E2")), vec![Rc::from("y")]); + let merged_enum = enum1.merge(&enum2); + if let VariableType::Enum(name, vals) = merged_enum { + assert!(name.unwrap().contains("E1 | E2")); + assert_eq!(vals.len(), 2); + } + + Ok(()) +} + +#[test] +fn variable_type_dot_operations() -> TestResult { + let mut obj_map = HashMap::new(); + obj_map.insert( + Rc::from("user"), + VariableType::Object(Rc::new(RefCell::new({ + let mut user_map = HashMap::new(); + user_map.insert(Rc::from("name"), VariableType::String); + user_map + }))), + ); + let obj = VariableType::Object(Rc::new(RefCell::new(obj_map))); + + // Test dot get + assert_eq!(obj.dot("user.name"), Some(VariableType::String)); + assert_eq!(obj.dot("user.nonexistent"), None); + assert_eq!(obj.dot("nonexistent"), None); + + // Test dot insert + let prev = obj.dot_insert("user.email", VariableType::String); + assert_eq!(prev, None); // No previous value + assert_eq!(obj.dot("user.email"), Some(VariableType::String)); + + // Test dot insert detached + let new_obj = obj + .dot_insert_detached("settings.theme", VariableType::String) + .expect("should insert successfully"); + assert_eq!(new_obj.dot("settings.theme"), Some(VariableType::String)); + assert_eq!(obj.dot("settings.theme"), None); + + // Test invalid dot operations on non-objects + assert_eq!(VariableType::String.dot("anything"), None); + assert_eq!( + VariableType::String.dot_insert("path", VariableType::Number), + None + ); + + Ok(()) +} + +#[test] +fn variable_type_conversions() -> TestResult { + // Test from serde_json Value + assert_eq!(VariableType::from(json!(null)), VariableType::Null); + assert_eq!(VariableType::from(json!(true)), VariableType::Bool); + assert_eq!(VariableType::from(json!(42)), VariableType::Number); + assert_eq!(VariableType::from(json!("hello")), VariableType::String); + + // Test array conversion with mixed types + let mixed_array = json!([1, "hello", true]); + let array_type = VariableType::from(mixed_array); + assert!(matches!(array_type, VariableType::Array(_))); + + // Test empty array + let empty_array = Vec::::new(); + let empty_type = VariableType::from(empty_array); + assert_eq!(empty_type, VariableType::Array(Rc::new(VariableType::Any))); + + // Test array reference conversion + let vec_ref = vec![json!(1), json!("test")]; + let ref_type = VariableType::from(&vec_ref); + assert!(matches!(ref_type, VariableType::Array(_))); + + let empty_vec_ref = Vec::::new(); + let empty_ref_type = VariableType::from(&empty_vec_ref); + assert_eq!( + empty_ref_type, + VariableType::Array(Rc::new(VariableType::Any)) + ); + + // Test object conversion + let obj = json!({"name": "Alice", "age": 30}); + let obj_type = VariableType::from(obj); + assert!(matches!(obj_type, VariableType::Object(_))); + if let VariableType::Object(obj_ref) = obj_type { + let obj_map = obj_ref.borrow(); + assert!(obj_map.contains_key(&Rc::from("name"))); + assert!(obj_map.contains_key(&Rc::from("age"))); + } + + // Test convenience methods + assert_eq!( + VariableType::Number.array(), + VariableType::Array(Rc::new(VariableType::Number)) + ); + assert_eq!(VariableType::default(), VariableType::Null); + + Ok(()) +} + +#[test] +fn variable_type_clone_operations() -> TestResult { + let mut inner_map = HashMap::new(); + inner_map.insert(Rc::from("value"), VariableType::String); + let inner_obj = VariableType::Object(Rc::new(RefCell::new(inner_map))); + + let mut outer_map = HashMap::new(); + outer_map.insert(Rc::from("inner"), inner_obj); + let outer_obj = VariableType::Object(Rc::new(RefCell::new(outer_map))); + + // Test shallow clone - shares references + let shallow = outer_obj.shallow_clone(); + if let (VariableType::Object(orig), VariableType::Object(clone)) = (&outer_obj, &shallow) { + assert!(Rc::ptr_eq(orig, clone)); + } + + // Test depth clone + let depth1 = outer_obj.depth_clone(1); + if let (VariableType::Object(orig), VariableType::Object(clone)) = (&outer_obj, &depth1) { + assert!(!Rc::ptr_eq(orig, clone)); // Outer different + + let orig = orig.borrow(); + let clone = clone.borrow(); + let orig_inner = orig.get("inner").unwrap(); + let clone_inner = clone.get("inner").unwrap(); + if let (VariableType::Object(orig_inner_ref), VariableType::Object(clone_inner_ref)) = + (orig_inner, clone_inner) + { + assert!(Rc::ptr_eq(orig_inner_ref, clone_inner_ref)); // Inner still shared at depth 1 + } + } + + Ok(()) +} From 070f6f8983141163d63294166fbe384b6e660ad9 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 18 Aug 2025 16:55:10 +0200 Subject: [PATCH 05/14] fix bindings --- bindings/nodejs/index.d.ts | 38 +++------ bindings/nodejs/src/decision.rs | 22 ++--- bindings/nodejs/src/engine.rs | 82 ++++++++++++++----- bindings/python/src/custom_node.rs | 14 ++-- bindings/python/src/decision.rs | 8 +- bindings/python/src/engine.rs | 10 ++- bindings/python/src/types.rs | 4 +- core/engine/Cargo.toml | 1 + core/engine/src/decision.rs | 28 ++++++- core/engine/src/engine.rs | 61 +++++++++++++- core/engine/src/error.rs | 30 ++++--- core/engine/src/handler/function_v1/mod.rs | 10 ++- core/engine/src/handler/function_v1/script.rs | 5 +- core/engine/src/handler/graph.rs | 35 ++++---- core/engine/src/lib.rs | 6 +- 15 files changed, 240 insertions(+), 114 deletions(-) diff --git a/bindings/nodejs/index.d.ts b/bindings/nodejs/index.d.ts index 0109f91e..111a624e 100644 --- a/bindings/nodejs/index.d.ts +++ b/bindings/nodejs/index.d.ts @@ -5,22 +5,23 @@ export interface ZenConfig { nodesInContext?: boolean + functionTimeoutMillis?: number } -export function overrideConfig(config: ZenConfig): void +export declare function overrideConfig(config: ZenConfig): void export interface ZenEvaluateOptions { maxDepth?: number - trace?: boolean + trace?: boolean | 'string' | 'reference' | 'referenceString' } export interface ZenEngineOptions { loader?: (key: string) => Promise customHandler?: (request: ZenEngineHandlerRequest) => Promise } -export function evaluateExpressionSync(expression: string, context?: any | undefined | null): any -export function evaluateUnaryExpressionSync(expression: string, context: any): boolean -export function renderTemplateSync(template: string, context: any): any -export function evaluateExpression(expression: string, context?: any | undefined | null): Promise -export function evaluateUnaryExpression(expression: string, context: any): Promise -export function renderTemplate(template: string, context: any): Promise +export declare function evaluateExpressionSync(expression: string, context?: any | undefined | null): any +export declare function evaluateUnaryExpressionSync(expression: string, context: any): boolean +export declare function renderTemplateSync(template: string, context: any): any +export declare function evaluateExpression(expression: string, context?: any | undefined | null): Promise +export declare function evaluateUnaryExpression(expression: string, context: any): Promise +export declare function renderTemplate(template: string, context: any): Promise export interface ZenEngineTrace { id: string name: string @@ -45,17 +46,17 @@ export interface DecisionNode { kind: string config: any } -export class ZenDecisionContent { +export declare class ZenDecisionContent { constructor(content: Buffer | object) toBuffer(): Buffer } -export class ZenDecision { +export declare class ZenDecision { constructor() evaluate(context: any, opts?: ZenEvaluateOptions | undefined | null): Promise safeEvaluate(context: any, opts?: ZenEvaluateOptions | undefined | null): Promise> validate(): void } -export class ZenEngine { +export declare class ZenEngine { constructor(options?: ZenEngineOptions | undefined | null) evaluate(key: string, context: any, opts?: ZenEvaluateOptions | undefined | null): Promise createDecision(content: ZenDecisionContent | Buffer | object): ZenDecision @@ -68,23 +69,10 @@ export class ZenEngine { */ dispose(): void } -export class ZenEngineHandlerRequest { +export declare class ZenEngineHandlerRequest { input: any node: DecisionNode constructor() getField(path: string): unknown getFieldRaw(path: string): unknown } - -// Custom definitions -type SafeResultSuccess = { - success: true; - data: T; -} - -type SafeResultError = { - success: false; - error: any; -} - -export type SafeResult = SafeResultSuccess | SafeResultError; \ No newline at end of file diff --git a/bindings/nodejs/src/decision.rs b/bindings/nodejs/src/decision.rs index aba951ea..98cc1924 100644 --- a/bindings/nodejs/src/decision.rs +++ b/bindings/nodejs/src/decision.rs @@ -3,12 +3,11 @@ use crate::engine::ZenEvaluateOptions; use crate::loader::DecisionLoader; use crate::mt::spawn_worker; use crate::safe_result::SafeResult; -use crate::types::ZenEngineResponse; use napi::anyhow::anyhow; use napi_derive::napi; use serde_json::Value; use std::sync::Arc; -use zen_engine::{Decision, EvaluationOptions}; +use zen_engine::{Decision, EvaluationSerializedOptions}; #[napi] pub struct ZenDecision(pub(crate) Arc>); @@ -26,34 +25,31 @@ impl ZenDecision { Err(anyhow!("Private constructor").into()) } - #[napi] + #[napi(ts_return_type = "Promise")] pub async fn evaluate( &self, context: Value, opts: Option, - ) -> napi::Result { + ) -> napi::Result { let decision = self.0.clone(); let result = spawn_worker(move || { let options = opts.unwrap_or_default(); async move { decision - .evaluate_with_opts( + .evaluate_serialized( context.into(), - EvaluationOptions { + EvaluationSerializedOptions { max_depth: options.max_depth, - trace: options.trace, + trace: options.trace.unwrap_or_default().0, }, ) .await - .map(ZenEngineResponse::from) - .map_err(|e| { - anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())) - }) } }) .await - .map_err(|_| anyhow!("Hook timed out"))??; + .map_err(|_| anyhow!("Hook timed out"))? + .map_err(|e| anyhow!(e))?; Ok(result) } @@ -63,7 +59,7 @@ impl ZenDecision { &self, context: Value, opts: Option, - ) -> SafeResult { + ) -> SafeResult { self.evaluate(context, opts).await.into() } diff --git a/bindings/nodejs/src/engine.rs b/bindings/nodejs/src/engine.rs index 31d8b955..88961d9c 100644 --- a/bindings/nodejs/src/engine.rs +++ b/bindings/nodejs/src/engine.rs @@ -1,22 +1,23 @@ +use std::str::FromStr; use std::sync::Arc; use napi::anyhow::{anyhow, Context}; -use napi::bindgen_prelude::{Buffer, Either3}; +use napi::bindgen_prelude::{Buffer, Either3, FromNapiValue, ToNapiValue}; +use napi::sys::{napi_env, napi_value}; use napi::threadsafe_function::{ErrorStrategy, ThreadSafeCallContext, ThreadsafeFunction}; -use napi::{Env, JsFunction, JsObject}; +use napi::{Env, JsFunction, JsObject, JsUnknown, NapiValue, ValueType}; use napi_derive::napi; use serde_json::Value; -use zen_engine::model::DecisionContent; -use zen_engine::{DecisionEngine, EvaluationOptions}; - use crate::content::ZenDecisionContent; use crate::custom_node::CustomNode; use crate::decision::ZenDecision; use crate::loader::DecisionLoader; use crate::mt::spawn_worker; use crate::safe_result::SafeResult; -use crate::types::{ZenEngineHandlerRequest, ZenEngineResponse}; +use crate::types::ZenEngineHandlerRequest; +use zen_engine::model::DecisionContent; +use zen_engine::{DecisionEngine, EvaluationSerializedOptions, EvaluationTraceKind}; #[napi] pub struct ZenEngine { @@ -26,17 +27,63 @@ pub struct ZenEngine { custom_handler_ref: Option>, } +#[derive(Debug, Default)] +pub struct JsEvaluationTraceKind(pub EvaluationTraceKind); + +impl FromNapiValue for JsEvaluationTraceKind { + unsafe fn from_napi_value(env: napi_env, napi_val: napi_value) -> napi::Result { + let js_value = JsUnknown::from_raw(env, napi_val)?; + + match js_value.get_type()? { + ValueType::Undefined | ValueType::Null => Ok(JsEvaluationTraceKind::default()), + ValueType::Boolean => { + let enabled = js_value.coerce_to_bool()?.get_value()?; + let kind = match enabled { + true => EvaluationTraceKind::Default, + false => EvaluationTraceKind::None, + }; + + Ok(JsEvaluationTraceKind(kind)) + } + ValueType::String => { + let kind_utf8 = js_value.coerce_to_string()?.into_utf8()?; + let kind_str = kind_utf8.as_str()?; + let kind = + EvaluationTraceKind::from_str(kind_str).context("invalid evaluation mode")?; + + Ok(JsEvaluationTraceKind(kind)) + } + _ => Err(anyhow!("Invalid trace setting").into()), + } + } +} + +impl ToNapiValue for JsEvaluationTraceKind { + unsafe fn to_napi_value(env: napi_env, val: Self) -> napi::Result { + match val.0 { + EvaluationTraceKind::None => ToNapiValue::to_napi_value(env, false), + EvaluationTraceKind::Default => ToNapiValue::to_napi_value(env, true), + _ => { + let mode_str: &'static str = val.0.into(); + ToNapiValue::to_napi_value(env, mode_str) + } + } + } +} + +#[derive(Debug)] #[napi(object)] pub struct ZenEvaluateOptions { pub max_depth: Option, - pub trace: Option, + #[napi(ts_type = "boolean | 'string' | 'reference' | 'referenceString'")] + pub trace: Option, } impl Default for ZenEvaluateOptions { fn default() -> Self { Self { max_depth: Some(5), - trace: Some(false), + trace: Some(JsEvaluationTraceKind::default()), } } } @@ -103,36 +150,33 @@ impl ZenEngine { }) } - #[napi] + #[napi(ts_return_type = "Promise")] pub async fn evaluate( &self, key: String, context: Value, opts: Option, - ) -> napi::Result { + ) -> napi::Result { let graph = self.graph.clone(); let result = spawn_worker(|| { let options = opts.unwrap_or_default(); async move { graph - .evaluate_with_opts( + .evaluate_serialized( key, context.into(), - EvaluationOptions { + EvaluationSerializedOptions { max_depth: options.max_depth, - trace: options.trace, + trace: options.trace.unwrap_or_default().0, }, ) .await - .map(ZenEngineResponse::from) - .map_err(|e| { - anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())) - }) } }) .await - .map_err(|_| anyhow!("Hook timed out"))??; + .map_err(|_| anyhow!("Hook timed out"))? + .map_err(|e| anyhow!(e))?; Ok(result) } @@ -173,7 +217,7 @@ impl ZenEngine { key: String, context: Value, opts: Option, - ) -> SafeResult { + ) -> SafeResult { self.evaluate(key, context, opts).await.into() } diff --git a/bindings/python/src/custom_node.rs b/bindings/python/src/custom_node.rs index 75093c7c..cfe529b2 100644 --- a/bindings/python/src/custom_node.rs +++ b/bindings/python/src/custom_node.rs @@ -1,4 +1,4 @@ -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use either::Either; use pyo3::types::PyDict; use pyo3::{Bound, IntoPyObjectExt, Py, PyAny, PyObject, PyResult, Python}; @@ -26,15 +26,17 @@ impl PyCustomNode { } fn extract_custom_node_response(py: Python<'_>, result: PyObject) -> NodeResult { - let dict = result.extract::>(py)?; - let response: NodeResponse = depythonize(&dict)?; + let dict = result + .extract::>(py) + .context("Failed to extract response")?; + let response: NodeResponse = depythonize(&dict).context("Failed to depythonize response")?; Ok(response) } impl CustomNodeAdapter for PyCustomNode { async fn handle(&self, request: CustomNodeRequest) -> NodeResult { let Some(callable) = &self.callback else { - return Err(anyhow!("Custom node handler not provided")); + return Err(anyhow!("Custom node handler not provided").into()); }; let maybe_result: PyResult<_> = Python::with_gil(|py| { @@ -57,10 +59,10 @@ impl CustomNodeAdapter for PyCustomNode { Ok(Either::Right(result_future)) }); - match maybe_result? { + match maybe_result.context("Failed to run custom node handler")? { Either::Left(result) => result, Either::Right(future) => { - let result = future.await?; + let result = future.await.context("Failed to run custom node handler")?; Python::with_gil(|py| extract_custom_node_response(py, result)) } } diff --git a/bindings/python/src/decision.rs b/bindings/python/src/decision.rs index 92cecfee..0a9e9ed8 100644 --- a/bindings/python/src/decision.rs +++ b/bindings/python/src/decision.rs @@ -77,12 +77,12 @@ impl PyZenDecision { ) .await .map(serde_json::to_value) + .map_err(|e| { + anyhow!(serde_json::to_string(&e).unwrap_or_else(|_| e.to_string())) + }) }) .await - .context("Failed to join threads")? - .map_err(|e| { - anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())) - })? + .context("Failed to join threads")?? .context("Failed to serialize result")?; Python::with_gil(|py| PyValue(value).into_py_any(py)) diff --git a/bindings/python/src/engine.rs b/bindings/python/src/engine.rs index 455229ec..838f31a6 100644 --- a/bindings/python/src/engine.rs +++ b/bindings/python/src/engine.rs @@ -152,12 +152,14 @@ impl PyZenEngine { ) .await .map(serde_json::to_value) + .map_err(|e| { + anyhow!( + serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string()) + ) + }) }) .await - .context("Failed to join threads")? - .map_err(|e| { - anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())) - })? + .context("Failed to join threads")?? .context("Failed to serialize result")?; Python::with_gil(|py| PyValue(value).into_py_any(py)) diff --git a/bindings/python/src/types.rs b/bindings/python/src/types.rs index 9537ae14..ec945278 100644 --- a/bindings/python/src/types.rs +++ b/bindings/python/src/types.rs @@ -102,7 +102,7 @@ impl From for PyNodeResponse { fn from(value: NodeResponse) -> Self { Self { output: value.output.to_value(), - trace_data: value.trace_data, + trace_data: value.trace_data.map(|v| v.to_value()), } } } @@ -111,7 +111,7 @@ impl From for NodeResponse { fn from(value: PyNodeResponse) -> Self { Self { output: value.output.into(), - trace_data: value.trace_data, + trace_data: value.trace_data.map(|v| v.into()), } } } diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 66bea3da..16493558 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -17,6 +17,7 @@ thiserror = { workspace = true } petgraph = { workspace = true } serde_json = { workspace = true, features = ["arbitrary_precision"] } serde = { workspace = true, features = ["derive", "rc"] } +strum = { workspace = true, features = ["derive"] } once_cell = { workspace = true } json_dotpath = { workspace = true } rust_decimal = { workspace = true, features = ["maths-nopanic"] } diff --git a/core/engine/src/decision.rs b/core/engine/src/decision.rs index 6a87a0a6..063a012a 100644 --- a/core/engine/src/decision.rs +++ b/core/engine/src/decision.rs @@ -1,10 +1,11 @@ -use crate::engine::EvaluationOptions; +use crate::engine::{EvaluationOptions, EvaluationSerializedOptions, EvaluationTraceKind}; use crate::handler::custom_node_adapter::{CustomNodeAdapter, NoopCustomNode}; use crate::handler::graph::{DecisionGraph, DecisionGraphConfig, DecisionGraphResponse}; use crate::loader::{CachedLoader, DecisionLoader, NoopLoader}; use crate::model::DecisionContent; use crate::util::validator_cache::ValidatorCache; use crate::{DecisionGraphValidationError, EvaluationError}; +use serde_json::Value; use std::sync::Arc; use zen_expression::variable::Variable; @@ -104,6 +105,31 @@ where Ok(response) } + pub async fn evaluate_serialized( + &self, + context: Variable, + options: EvaluationSerializedOptions, + ) -> Result { + let response = self + .evaluate_with_opts( + context, + EvaluationOptions { + trace: Some(options.trace != EvaluationTraceKind::None), + max_depth: options.max_depth, + }, + ) + .await; + + match response { + Ok(ok) => Ok(ok + .serialize_with_mode(serde_json::value::Serializer, options.trace) + .unwrap_or_default()), + Err(err) => Err(err + .serialize_with_mode(serde_json::value::Serializer, options.trace) + .unwrap_or_default()), + } + } + pub fn validate(&self) -> Result<(), DecisionGraphValidationError> { let decision_graph = DecisionGraph::try_new(DecisionGraphConfig { content: self.content.clone(), diff --git a/core/engine/src/engine.rs b/core/engine/src/engine.rs index ab9e2455..bd659921 100644 --- a/core/engine/src/engine.rs +++ b/core/engine/src/engine.rs @@ -1,12 +1,13 @@ -use std::future::Future; -use std::sync::Arc; - use crate::decision::Decision; use crate::handler::custom_node_adapter::{CustomNodeAdapter, NoopCustomNode}; use crate::handler::graph::DecisionGraphResponse; use crate::loader::{ClosureLoader, DecisionLoader, LoaderResponse, LoaderResult, NoopLoader}; use crate::model::DecisionContent; use crate::EvaluationError; +use serde_json::Value; +use std::future::Future; +use std::sync::Arc; +use strum::{EnumString, IntoStaticStr}; use zen_expression::variable::Variable; /// Structure used for generating and evaluating JDM decisions @@ -26,6 +27,41 @@ pub struct EvaluationOptions { pub max_depth: Option, } +#[derive(Debug, Default)] +pub struct EvaluationSerializedOptions { + pub trace: EvaluationTraceKind, + pub max_depth: Option, +} + +#[derive(Debug, Default, PartialEq, Eq, EnumString, IntoStaticStr)] +#[strum(serialize_all = "camelCase")] +pub enum EvaluationTraceKind { + #[default] + None, + Default, + String, + Reference, + ReferenceString, +} + +impl EvaluationTraceKind { + pub fn serialize_trace(&self, trace: &Variable) -> Value { + match self { + EvaluationTraceKind::None => Value::Null, + EvaluationTraceKind::Default => serde_json::to_value(&trace).unwrap_or_default(), + EvaluationTraceKind::String => { + Value::String(serde_json::to_string(&trace).unwrap_or_default()) + } + EvaluationTraceKind::Reference => { + serde_json::to_value(&trace.serialize_ref()).unwrap_or_default() + } + EvaluationTraceKind::ReferenceString => { + Value::String(serde_json::to_string(&trace.serialize_ref()).unwrap_or_default()) + } + } + } +} + impl Default for DecisionEngine { fn default() -> Self { Self { @@ -99,6 +135,25 @@ impl DecisionEngine decision.evaluate_with_opts(context, options).await } + pub async fn evaluate_serialized( + &self, + key: K, + context: Variable, + options: EvaluationSerializedOptions, + ) -> Result + where + K: AsRef, + { + let content = self + .loader + .load(key.as_ref()) + .await + .map_err(|err| Value::String(err.to_string()))?; + + let decision = self.create_decision(content); + decision.evaluate_serialized(context, options).await + } + /// Creates a decision from DecisionContent, exists for easier binding creation pub fn create_decision(&self, content: Arc) -> Decision { Decision::from(content) diff --git a/core/engine/src/error.rs b/core/engine/src/error.rs index fb4e396a..b49c4cc4 100644 --- a/core/engine/src/error.rs +++ b/core/engine/src/error.rs @@ -1,3 +1,4 @@ +use crate::engine::EvaluationTraceKind; use crate::handler::graph::DecisionGraphValidationError; pub use crate::handler::node::NodeError; use crate::loader::LoaderError; @@ -26,12 +27,17 @@ pub enum EvaluationError { Validation(Value), } -impl Serialize for EvaluationError { - fn serialize(&self, serializer: S) -> Result +impl EvaluationError { + pub fn serialize_with_mode( + &self, + serializer: S, + mode: EvaluationTraceKind, + ) -> Result where S: Serializer, { let mut map = serializer.serialize_map(None)?; + match self { EvaluationError::DepthLimitExceeded => { map.serialize_entry("type", "DepthLimitExceeded")?; @@ -50,21 +56,14 @@ impl Serialize for EvaluationError { } => { map.serialize_entry("nodeId", node_id.as_str())?; map.serialize_entry("source", &source.to_string())?; - if let Some(trace) = &trace { - map.serialize_entry( - "trace", - &serde_json::to_value(&trace.serialize_ref()).unwrap(), - )?; + map.serialize_entry("trace", &mode.serialize_trace(trace))?; } } NodeError::PartialTrace { trace, message } => { map.serialize_entry("source", message.as_str())?; if let Some(trace) = &trace { - map.serialize_entry( - "trace", - &serde_json::to_value(&trace.serialize_ref()).unwrap(), - )?; + map.serialize_entry("trace", &mode.serialize_trace(trace))?; } } } @@ -95,6 +94,15 @@ impl Serialize for EvaluationError { } } +impl Serialize for EvaluationError { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.serialize_with_mode(serializer, Default::default()) + } +} + impl From for Box { fn from(error: LoaderError) -> Self { Box::new(EvaluationError::LoaderError(error.into())) diff --git a/core/engine/src/handler/function_v1/mod.rs b/core/engine/src/handler/function_v1/mod.rs index 79dcd6de..37062b46 100644 --- a/core/engine/src/handler/function_v1/mod.rs +++ b/core/engine/src/handler/function_v1/mod.rs @@ -5,6 +5,7 @@ use crate::handler::node::{NodeRequest, NodeResponse, NodeResult}; use crate::model::{DecisionNodeKind, FunctionNodeContent}; use anyhow::anyhow; use rquickjs::Runtime; +use serde_json::Value; use zen_expression::variable::ToVariable; pub(crate) mod runtime; @@ -43,7 +44,14 @@ impl FunctionHandler { let response = result_response?; Ok(NodeResponse { output: response.output.clone(), - trace_data: self.trace.then(|| response.to_variable()), + trace_data: self + .trace + .then(|| FunctionTrace { log: response.log }.to_variable()), }) } } + +#[derive(ToVariable)] +struct FunctionTrace { + log: Vec, +} diff --git a/core/engine/src/handler/function_v1/script.rs b/core/engine/src/handler/function_v1/script.rs index 358d285e..c6f4a00a 100644 --- a/core/engine/src/handler/function_v1/script.rs +++ b/core/engine/src/handler/function_v1/script.rs @@ -5,12 +5,11 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use std::fmt::Debug; use std::rc::Rc; -use zen_expression::variable::{ToVariable, Variable}; +use zen_expression::variable::Variable; -#[derive(Debug, ToVariable, Deserialize)] +#[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct EvaluateResponse { - #[serde(skip)] pub output: Variable, pub log: Vec, } diff --git a/core/engine/src/handler/graph.rs b/core/engine/src/handler/graph.rs index ab39c00d..21e9808c 100644 --- a/core/engine/src/handler/graph.rs +++ b/core/engine/src/handler/graph.rs @@ -1,3 +1,4 @@ +use crate::engine::EvaluationTraceKind; use crate::handler::custom_node_adapter::{CustomNodeAdapter, CustomNodeRequest}; use crate::handler::decision::DecisionHandler; use crate::handler::expression::ExpressionHandler; @@ -19,7 +20,7 @@ use anyhow::anyhow; use petgraph::algo::is_cyclic_directed; use serde::ser::SerializeMap; use serde::{Deserialize, Serialize, Serializer}; -use serde_json::{Map, Value}; +use serde_json::Value; use std::hash::{DefaultHasher, Hash, Hasher}; use std::rc::Rc; use std::sync::Arc; @@ -540,28 +541,22 @@ pub struct DecisionGraphResponse { } impl DecisionGraphResponse { - pub fn serialize_ref(&self) -> Value { - let mut map = Map::with_capacity(3); - map.insert( - "performance".to_string(), - Value::String(self.performance.clone()), - ); - map.insert("result".to_string(), self.result.to_value()); - + pub fn serialize_with_mode( + &self, + serializer: S, + mode: EvaluationTraceKind, + ) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(None)?; + map.serialize_entry("performance", &self.performance)?; + map.serialize_entry("result", &self.result)?; if let Some(trace) = &self.trace { - let trace_map = trace - .iter() - .map(|(k, v)| (Rc::from(k.as_str()), v.to_variable())) - .collect::, Variable>>(); - - let joined_variable = Variable::from_object(trace_map); - map.insert( - "trace".to_string(), - serde_json::to_value(joined_variable).unwrap_or_default(), - ); + map.serialize_entry("trace", &mode.serialize_trace(&trace.to_variable()))?; } - Value::Object(map) + map.end() } } diff --git a/core/engine/src/lib.rs b/core/engine/src/lib.rs index 80804090..35323827 100644 --- a/core/engine/src/lib.rs +++ b/core/engine/src/lib.rs @@ -125,7 +125,7 @@ mod config; mod decision; mod engine; -mod error; +pub mod error; pub mod handler; pub mod loader; #[path = "model/mod.rs"] @@ -134,7 +134,9 @@ mod util; pub use config::ZEN_CONFIG; pub use decision::Decision; -pub use engine::{DecisionEngine, EvaluationOptions}; +pub use engine::{ + DecisionEngine, EvaluationOptions, EvaluationSerializedOptions, EvaluationTraceKind, +}; pub use error::EvaluationError; pub use handler::graph::DecisionGraphResponse; pub use handler::graph::DecisionGraphTrace; From 62776a9768606ab03a56e27d91707354e3971679 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Wed, 20 Aug 2025 12:01:49 +0200 Subject: [PATCH 06/14] first draft --- core/engine/Cargo.toml | 1 + core/engine/tests/engine.rs | 58 + core/engine/tests/snapshots/.gitignore | 1 + ...engine__account-dormancy-management_0.snap | 219 +++ ...ne__affiliate-commission-calculator_0.snap | 151 ++ ...airline-loyalty-points-calculations_0.snap | 212 +++ ...engine__airline-upgrade-eligibility_0.snap | 450 ++++++ .../engine/tests/snapshots/engine__aml_0.snap | 347 ++++ .../engine/tests/snapshots/engine__aml_1.snap | 375 +++++ .../engine/tests/snapshots/engine__aml_2.snap | 354 +++++ ...engine__application-risk-assessment_0.snap | 441 +++++ ...__auto-insurance-premium-calculator_0.snap | 355 +++++ .../engine__booking-fraud-detection_0.snap | 329 ++++ ...ine__booking-personalization-system_0.snap | 482 ++++++ ...engine__care-team-assignment-system_0.snap | 783 +++++++++ ...gine__cellular-data-rollover-system_0.snap | 230 +++ .../engine__claim-validation-system_0.snap | 227 +++ ...ne__clinical-lab-result-interpreter_0.snap | 478 ++++++ .../engine__clinical-pathway-selection_0.snap | 638 ++++++++ ...engine__clinical-treatment-protocol_0.snap | 297 ++++ ...clinical-trial-eligibility-screener_0.snap | 569 +++++++ .../snapshots/engine__company-analysis_0.snap | 168 ++ .../snapshots/engine__company-analysis_1.snap | 181 +++ .../snapshots/engine__company-analysis_2.snap | 181 +++ .../engine__credit-limit-adjustment_0.snap | 527 ++++++ ...engine__customer-eligibility-engine_0.snap | 467 ++++++ .../engine__customer-lifetime-value_0.snap | 238 +++ ...ustomer-onboarding-kyc-verification_0.snap | 648 ++++++++ ...engine__customer-service-escalation_0.snap | 79 + .../engine__decision-table-discounts_0.snap | 72 + .../engine__decision-table-discounts_1.snap | 94 ++ .../engine__decision-table-discounts_2.snap | 72 + .../engine__decision-table-shipping_0.snap | 84 + .../engine__decision-table-shipping_1.snap | 84 + .../engine__decision-table-shipping_10.snap | 81 + .../engine__decision-table-shipping_11.snap | 73 + .../engine__decision-table-shipping_2.snap | 84 + .../engine__decision-table-shipping_3.snap | 81 + .../engine__decision-table-shipping_4.snap | 81 + .../engine__decision-table-shipping_5.snap | 81 + .../engine__decision-table-shipping_6.snap | 81 + .../engine__decision-table-shipping_7.snap | 81 + .../engine__decision-table-shipping_8.snap | 81 + .../engine__decision-table-shipping_9.snap | 81 + .../engine__delivery-route-optimizer_0.snap | 222 +++ ...ngine__device-compatibility-checker_0.snap | 145 ++ ...ne__disaster-relief-fund-allocation_0.snap | 335 ++++ ...ine__dynamic-fx-rate-pricing-system_0.snap | 107 ++ ...ic-marketplace-comission-calculator_0.snap | 204 +++ ...e__dynamic-shipping-cost-calculator_0.snap | 255 +++ .../engine__dynamic-tarrif-engine_0.snap | 171 ++ .../engine__dynamic-ticket-pricing_0.snap | 255 +++ .../engine__empty-column-with-space_0.snap | 51 + .../engine__empty-column-with-space_1.snap | 51 + .../engine__empty-column-without-space_0.snap | 51 + .../engine__empty-column-without-space_1.snap | 51 + ...__environment-compliance-assessment_0.snap | 438 +++++ .../engine__expression-default_0.snap | 41 + .../engine__expression-default_1.snap | 43 + .../engine__expression-default_2.snap | 47 + .../engine__expression-default_3.snap | 41 + .../engine__expression-default_4.snap | 41 + .../engine__expression-fields_0.snap | 65 + .../engine__expression-fields_1.snap | 65 + .../snapshots/engine__expression-loop_0.snap | 115 ++ .../engine__expression-passthrough_0.snap | 49 + .../engine__expression-passthrough_1.snap | 51 + .../engine__expression-passthrough_2.snap | 51 + .../engine__expression-passthrough_3.snap | 53 + .../engine__expression-passthrough_4.snap | 63 + .../engine__expression-table-map_0.snap | 263 +++ .../engine__expression-table-map_1.snap | 224 +++ .../engine__expression-table-map_2.snap | 263 +++ .../engine__flash-sale-eligibility_0.snap | 276 ++++ ...e__flight-ancillary-recommendations_0.snap | 630 ++++++++ ...ne__flight-dispatch-decision-system_0.snap | 752 +++++++++ ...ne__flight-rebooking-fee-calculator_0.snap | 309 ++++ .../engine__government-assistance_0.snap | 143 ++ .../engine__grant-funding-distribution_0.snap | 287 ++++ ...zardous-materials-management-system_0.snap | 164 ++ ...__immigration-eligibility-evaluator_0.snap | 791 +++++++++ .../engine__import-duties-calculator_0.snap | 207 +++ .../engine__insurance-agent-commission_0.snap | 122 ++ .../engine__insurance-breakdown_0.snap | 181 +++ .../engine__insurance-breakdown_1.snap | 176 ++ .../engine__insurance-breakdown_2.snap | 176 ++ .../engine__insurance-breakdown_3.snap | 181 +++ .../engine__insurance-breakdown_4.snap | 181 +++ ...gine__insurance-coverage-calculator_0.snap | 255 +++ ...gine__insurance-prior-authorization_0.snap | 180 +++ ...engine__insurance-underwriting-risk_0.snap | 276 ++++ ...nternational-roaming-policy-manager_0.snap | 183 +++ ...gine__last-mile-delivery-assignment_0.snap | 561 +++++++ .../engine__legacy-plan-management_0.snap | 377 +++++ .../snapshots/engine__loan-approval_0.snap | 460 ++++++ ...etplace-listing-verification-system_0.snap | 361 +++++ ...__marketplace-seller-grading-system_0.snap | 343 ++++ ...medical-appointment-priority-system_0.snap | 391 +++++ ...ngine__medication-dosage-calculator_0.snap | 163 ++ .../tests/snapshots/engine__merch-bags_0.snap | 58 + .../tests/snapshots/engine__merch-bags_1.snap | 60 + .../tests/snapshots/engine__merch-bags_2.snap | 63 + .../snapshots/engine__multi-switch_0.snap | 81 + .../snapshots/engine__multi-switch_1.snap | 126 ++ .../snapshots/engine__multi-switch_2.snap | 177 +++ .../snapshots/engine__multi-switch_3.snap | 162 ++ .../snapshots/engine__multi-switch_4.snap | 147 ++ ..._municipal-permit-evaluation-system_0.snap | 269 ++++ .../engine__mvno-partner-enablement_0.snap | 177 +++ .../snapshots/engine__nested-request_0.snap | 62 + .../engine__online-checkin-eligibility_0.snap | 269 ++++ .../engine__order-consolidation-system_0.snap | 678 ++++++++ .../engine__partner-revenue-sharing_0.snap | 126 ++ .../engine__patient-triage-system_0.snap | 281 ++++ ..._payment-routing-and-fee-calculator_0.snap | 584 +++++++ .../engine__policy-discount-calculator_0.snap | 346 ++++ ...engine__policy-eligibility-analyzer_0.snap | 303 ++++ .../engine__portfolio-risk-monitor_0.snap | 1415 +++++++++++++++++ ...ine__preventive-care-recommendation_0.snap | 298 ++++ .../engine__product-listing-scoring_0.snap | 308 ++++ .../engine__realtime-fraud-detection_0.snap | 185 +++ ...engine__regional-compliance-manager_0.snap | 193 +++ .../engine__returns-and-refund-policy_0.snap | 334 ++++ .../engine__returns-processing-system_0.snap | 396 +++++ ...school-district-resource-allocation_0.snap | 316 ++++ .../engine__seat-map-optimization_0.snap | 266 ++++ .../engine__seller-approval-workflow_0.snap | 373 +++++ .../engine__seller-fee-calculator_0.snap | 157 ++ ...service-level-agreement-enforcement_0.snap | 599 +++++++ .../tests/snapshots/engine__set-fee_0.snap | 127 ++ .../tests/snapshots/engine__set-fee_1.snap | 98 ++ .../tests/snapshots/engine__set-fee_2.snap | 127 ++ .../engine__shipping-carrier-selector_0.snap | 328 ++++ ...ne__smart-financial-product-matcher_0.snap | 178 +++ .../engine__supply-chain-risk_0.snap | 300 ++++ .../tests/snapshots/engine__table-loop_0.snap | 51 + .../snapshots/engine__tax-exemption_0.snap | 161 ++ ...raffic-violation-penalty-calculator_0.snap | 292 ++++ ...__transaction-compliance-classifier_0.snap | 605 +++++++ .../engine__vehicle-claims-resolution_0.snap | 205 +++ .../engine__warehouse-cross-docking_0.snap | 379 +++++ .../engine__warehouse-storage-location_0.snap | 327 ++++ .../graphs/account-dormancy-management.json | 245 +++ .../affiliate-commission-calculator.json | 228 +++ .../airline-loyalty-points-calculations.json | 285 ++++ .../graphs/airline-upgrade-eligibility.json | 466 ++++++ .../graphs/application-risk-assessment.json | 474 ++++++ .../auto-insurance-premium-calculator.json | 412 +++++ test-data/graphs/booking-fraud-detection.json | 428 +++++ .../booking-personalization-system.json | 553 +++++++ .../graphs/care-team-assignment-system.json | 585 +++++++ .../graphs/cellular-data-rollover-system.json | 281 ++++ test-data/graphs/claim-validation-system.json | 307 ++++ .../clinical-lab-result-interpreter.json | 433 +++++ .../graphs/clinical-pathway-selection.json | 454 ++++++ .../graphs/clinical-treatment-protocol.json | 474 ++++++ .../clinical-trial-eligibility-screener.json | 502 ++++++ test-data/graphs/credit-limit-adjustment.json | 479 ++++++ .../graphs/customer-eligibility-engine.json | 551 +++++++ test-data/graphs/customer-lifetime-value.json | 200 +++ .../customer-onboarding-kyc-verification.json | 611 +++++++ .../graphs/customer-service-escalation.json | 191 +++ .../graphs/delivery-route-optimizer.json | 271 ++++ .../graphs/device-compatibility-checker.json | 303 ++++ .../disaster-relief-fund-allocation.json | 296 ++++ .../dynamic-fx-rate-pricing-system.json | 237 +++ ...amic-marketplace-comission-calculator.json | 242 +++ .../dynamic-shipping-cost-calculator.json | 378 +++++ test-data/graphs/dynamic-tarrif-engine.json | 289 ++++ test-data/graphs/dynamic-ticket-pricing.json | 325 ++++ .../environment-compliance-assessment.json | 386 +++++ test-data/graphs/flash-sale-eligibility.json | 366 +++++ .../flight-ancillary-recommendations.json | 436 +++++ .../flight-dispatch-decision-system.json | 455 ++++++ .../flight-rebooking-fee-calculator.json | 406 +++++ test-data/graphs/government-assistance.json | 299 ++++ .../graphs/grant-funding-distribution.json | 307 ++++ ...hazardous-materials-management-system.json | 414 +++++ .../immigration-eligibility-evaluator.json | 765 +++++++++ .../graphs/import-duties-calculator.json | 318 ++++ .../graphs/insurance-agent-commission.json | 228 +++ .../graphs/insurance-coverage-calculator.json | 362 +++++ .../graphs/insurance-prior-authorization.json | 467 ++++++ .../graphs/insurance-underwriting-risk.json | 321 ++++ .../international-roaming-policy-manager.json | 199 +++ .../graphs/last-mile-delivery-assignment.json | 373 +++++ test-data/graphs/legacy-plan-management.json | 434 +++++ test-data/graphs/loan-approval.json | 469 ++++++ ...rketplace-listing-verification-system.json | 334 ++++ .../marketplace-seller-grading-system.json | 436 +++++ .../medical-appointment-priority-system.json | 446 ++++++ .../graphs/medication-dosage-calculator.json | 318 ++++ .../municipal-permit-evaluation-system.json | 364 +++++ test-data/graphs/mvno-partner-enablement.json | 313 ++++ .../graphs/online-checkin-eligibility.json | 285 ++++ .../graphs/order-consolidation-system.json | 493 ++++++ test-data/graphs/partner-revenue-sharing.json | 244 +++ test-data/graphs/patient-triage-system.json | 406 +++++ .../payment-routing-and-fee-calculator.json | 475 ++++++ .../graphs/policy-discount-calculator.json | 307 ++++ .../graphs/policy-eligibility-analyzer.json | 299 ++++ test-data/graphs/portfolio-risk-monitor.json | 588 +++++++ .../preventive-care-recommendation.json | 370 +++++ test-data/graphs/product-listing-scoring.json | 358 +++++ .../graphs/realtime-fraud-detection.json | 235 +++ .../graphs/regional-compliance-manager.json | 278 ++++ .../graphs/returns-and-refund-policy.json | 366 +++++ .../graphs/returns-processing-system.json | 448 ++++++ .../school-district-resource-allocation.json | 282 ++++ test-data/graphs/seat-map-optimization.json | 325 ++++ .../graphs/seller-approval-workflow.json | 383 +++++ test-data/graphs/seller-fee-calculator.json | 307 ++++ .../service-level-agreement-enforcement.json | 575 +++++++ .../graphs/shipping-carrier-selector.json | 379 +++++ .../smart-financial-product-matcher.json | 249 +++ test-data/graphs/supply-chain-risk.json | 316 ++++ test-data/graphs/tax-exemption.json | 295 ++++ .../traffic-violation-penalty-calculator.json | 436 +++++ .../transaction-compliance-classifier.json | 525 ++++++ .../graphs/vehicle-claims-resolution.json | 310 ++++ test-data/graphs/warehouse-cross-docking.json | 313 ++++ .../graphs/warehouse-storage-location.json | 345 ++++ 222 files changed, 64529 insertions(+) create mode 100644 core/engine/tests/snapshots/.gitignore create mode 100644 core/engine/tests/snapshots/engine__account-dormancy-management_0.snap create mode 100644 core/engine/tests/snapshots/engine__affiliate-commission-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__airline-loyalty-points-calculations_0.snap create mode 100644 core/engine/tests/snapshots/engine__airline-upgrade-eligibility_0.snap create mode 100644 core/engine/tests/snapshots/engine__aml_0.snap create mode 100644 core/engine/tests/snapshots/engine__aml_1.snap create mode 100644 core/engine/tests/snapshots/engine__aml_2.snap create mode 100644 core/engine/tests/snapshots/engine__application-risk-assessment_0.snap create mode 100644 core/engine/tests/snapshots/engine__auto-insurance-premium-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__booking-fraud-detection_0.snap create mode 100644 core/engine/tests/snapshots/engine__booking-personalization-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__care-team-assignment-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__cellular-data-rollover-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__claim-validation-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__clinical-lab-result-interpreter_0.snap create mode 100644 core/engine/tests/snapshots/engine__clinical-pathway-selection_0.snap create mode 100644 core/engine/tests/snapshots/engine__clinical-treatment-protocol_0.snap create mode 100644 core/engine/tests/snapshots/engine__clinical-trial-eligibility-screener_0.snap create mode 100644 core/engine/tests/snapshots/engine__company-analysis_0.snap create mode 100644 core/engine/tests/snapshots/engine__company-analysis_1.snap create mode 100644 core/engine/tests/snapshots/engine__company-analysis_2.snap create mode 100644 core/engine/tests/snapshots/engine__credit-limit-adjustment_0.snap create mode 100644 core/engine/tests/snapshots/engine__customer-eligibility-engine_0.snap create mode 100644 core/engine/tests/snapshots/engine__customer-lifetime-value_0.snap create mode 100644 core/engine/tests/snapshots/engine__customer-onboarding-kyc-verification_0.snap create mode 100644 core/engine/tests/snapshots/engine__customer-service-escalation_0.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-discounts_0.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-discounts_1.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-discounts_2.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_0.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_1.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_10.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_11.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_2.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_3.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_4.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_5.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_6.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_7.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_8.snap create mode 100644 core/engine/tests/snapshots/engine__decision-table-shipping_9.snap create mode 100644 core/engine/tests/snapshots/engine__delivery-route-optimizer_0.snap create mode 100644 core/engine/tests/snapshots/engine__device-compatibility-checker_0.snap create mode 100644 core/engine/tests/snapshots/engine__disaster-relief-fund-allocation_0.snap create mode 100644 core/engine/tests/snapshots/engine__dynamic-fx-rate-pricing-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__dynamic-marketplace-comission-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__dynamic-shipping-cost-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__dynamic-tarrif-engine_0.snap create mode 100644 core/engine/tests/snapshots/engine__dynamic-ticket-pricing_0.snap create mode 100644 core/engine/tests/snapshots/engine__empty-column-with-space_0.snap create mode 100644 core/engine/tests/snapshots/engine__empty-column-with-space_1.snap create mode 100644 core/engine/tests/snapshots/engine__empty-column-without-space_0.snap create mode 100644 core/engine/tests/snapshots/engine__empty-column-without-space_1.snap create mode 100644 core/engine/tests/snapshots/engine__environment-compliance-assessment_0.snap create mode 100644 core/engine/tests/snapshots/engine__expression-default_0.snap create mode 100644 core/engine/tests/snapshots/engine__expression-default_1.snap create mode 100644 core/engine/tests/snapshots/engine__expression-default_2.snap create mode 100644 core/engine/tests/snapshots/engine__expression-default_3.snap create mode 100644 core/engine/tests/snapshots/engine__expression-default_4.snap create mode 100644 core/engine/tests/snapshots/engine__expression-fields_0.snap create mode 100644 core/engine/tests/snapshots/engine__expression-fields_1.snap create mode 100644 core/engine/tests/snapshots/engine__expression-loop_0.snap create mode 100644 core/engine/tests/snapshots/engine__expression-passthrough_0.snap create mode 100644 core/engine/tests/snapshots/engine__expression-passthrough_1.snap create mode 100644 core/engine/tests/snapshots/engine__expression-passthrough_2.snap create mode 100644 core/engine/tests/snapshots/engine__expression-passthrough_3.snap create mode 100644 core/engine/tests/snapshots/engine__expression-passthrough_4.snap create mode 100644 core/engine/tests/snapshots/engine__expression-table-map_0.snap create mode 100644 core/engine/tests/snapshots/engine__expression-table-map_1.snap create mode 100644 core/engine/tests/snapshots/engine__expression-table-map_2.snap create mode 100644 core/engine/tests/snapshots/engine__flash-sale-eligibility_0.snap create mode 100644 core/engine/tests/snapshots/engine__flight-ancillary-recommendations_0.snap create mode 100644 core/engine/tests/snapshots/engine__flight-dispatch-decision-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__flight-rebooking-fee-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__government-assistance_0.snap create mode 100644 core/engine/tests/snapshots/engine__grant-funding-distribution_0.snap create mode 100644 core/engine/tests/snapshots/engine__hazardous-materials-management-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__immigration-eligibility-evaluator_0.snap create mode 100644 core/engine/tests/snapshots/engine__import-duties-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__insurance-agent-commission_0.snap create mode 100644 core/engine/tests/snapshots/engine__insurance-breakdown_0.snap create mode 100644 core/engine/tests/snapshots/engine__insurance-breakdown_1.snap create mode 100644 core/engine/tests/snapshots/engine__insurance-breakdown_2.snap create mode 100644 core/engine/tests/snapshots/engine__insurance-breakdown_3.snap create mode 100644 core/engine/tests/snapshots/engine__insurance-breakdown_4.snap create mode 100644 core/engine/tests/snapshots/engine__insurance-coverage-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__insurance-prior-authorization_0.snap create mode 100644 core/engine/tests/snapshots/engine__insurance-underwriting-risk_0.snap create mode 100644 core/engine/tests/snapshots/engine__international-roaming-policy-manager_0.snap create mode 100644 core/engine/tests/snapshots/engine__last-mile-delivery-assignment_0.snap create mode 100644 core/engine/tests/snapshots/engine__legacy-plan-management_0.snap create mode 100644 core/engine/tests/snapshots/engine__loan-approval_0.snap create mode 100644 core/engine/tests/snapshots/engine__marketplace-listing-verification-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__marketplace-seller-grading-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__medical-appointment-priority-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__medication-dosage-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__merch-bags_0.snap create mode 100644 core/engine/tests/snapshots/engine__merch-bags_1.snap create mode 100644 core/engine/tests/snapshots/engine__merch-bags_2.snap create mode 100644 core/engine/tests/snapshots/engine__multi-switch_0.snap create mode 100644 core/engine/tests/snapshots/engine__multi-switch_1.snap create mode 100644 core/engine/tests/snapshots/engine__multi-switch_2.snap create mode 100644 core/engine/tests/snapshots/engine__multi-switch_3.snap create mode 100644 core/engine/tests/snapshots/engine__multi-switch_4.snap create mode 100644 core/engine/tests/snapshots/engine__municipal-permit-evaluation-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__mvno-partner-enablement_0.snap create mode 100644 core/engine/tests/snapshots/engine__nested-request_0.snap create mode 100644 core/engine/tests/snapshots/engine__online-checkin-eligibility_0.snap create mode 100644 core/engine/tests/snapshots/engine__order-consolidation-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__partner-revenue-sharing_0.snap create mode 100644 core/engine/tests/snapshots/engine__patient-triage-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__payment-routing-and-fee-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__policy-discount-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__policy-eligibility-analyzer_0.snap create mode 100644 core/engine/tests/snapshots/engine__portfolio-risk-monitor_0.snap create mode 100644 core/engine/tests/snapshots/engine__preventive-care-recommendation_0.snap create mode 100644 core/engine/tests/snapshots/engine__product-listing-scoring_0.snap create mode 100644 core/engine/tests/snapshots/engine__realtime-fraud-detection_0.snap create mode 100644 core/engine/tests/snapshots/engine__regional-compliance-manager_0.snap create mode 100644 core/engine/tests/snapshots/engine__returns-and-refund-policy_0.snap create mode 100644 core/engine/tests/snapshots/engine__returns-processing-system_0.snap create mode 100644 core/engine/tests/snapshots/engine__school-district-resource-allocation_0.snap create mode 100644 core/engine/tests/snapshots/engine__seat-map-optimization_0.snap create mode 100644 core/engine/tests/snapshots/engine__seller-approval-workflow_0.snap create mode 100644 core/engine/tests/snapshots/engine__seller-fee-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__service-level-agreement-enforcement_0.snap create mode 100644 core/engine/tests/snapshots/engine__set-fee_0.snap create mode 100644 core/engine/tests/snapshots/engine__set-fee_1.snap create mode 100644 core/engine/tests/snapshots/engine__set-fee_2.snap create mode 100644 core/engine/tests/snapshots/engine__shipping-carrier-selector_0.snap create mode 100644 core/engine/tests/snapshots/engine__smart-financial-product-matcher_0.snap create mode 100644 core/engine/tests/snapshots/engine__supply-chain-risk_0.snap create mode 100644 core/engine/tests/snapshots/engine__table-loop_0.snap create mode 100644 core/engine/tests/snapshots/engine__tax-exemption_0.snap create mode 100644 core/engine/tests/snapshots/engine__traffic-violation-penalty-calculator_0.snap create mode 100644 core/engine/tests/snapshots/engine__transaction-compliance-classifier_0.snap create mode 100644 core/engine/tests/snapshots/engine__vehicle-claims-resolution_0.snap create mode 100644 core/engine/tests/snapshots/engine__warehouse-cross-docking_0.snap create mode 100644 core/engine/tests/snapshots/engine__warehouse-storage-location_0.snap create mode 100644 test-data/graphs/account-dormancy-management.json create mode 100644 test-data/graphs/affiliate-commission-calculator.json create mode 100644 test-data/graphs/airline-loyalty-points-calculations.json create mode 100644 test-data/graphs/airline-upgrade-eligibility.json create mode 100644 test-data/graphs/application-risk-assessment.json create mode 100644 test-data/graphs/auto-insurance-premium-calculator.json create mode 100644 test-data/graphs/booking-fraud-detection.json create mode 100644 test-data/graphs/booking-personalization-system.json create mode 100644 test-data/graphs/care-team-assignment-system.json create mode 100644 test-data/graphs/cellular-data-rollover-system.json create mode 100644 test-data/graphs/claim-validation-system.json create mode 100644 test-data/graphs/clinical-lab-result-interpreter.json create mode 100644 test-data/graphs/clinical-pathway-selection.json create mode 100644 test-data/graphs/clinical-treatment-protocol.json create mode 100644 test-data/graphs/clinical-trial-eligibility-screener.json create mode 100644 test-data/graphs/credit-limit-adjustment.json create mode 100644 test-data/graphs/customer-eligibility-engine.json create mode 100644 test-data/graphs/customer-lifetime-value.json create mode 100644 test-data/graphs/customer-onboarding-kyc-verification.json create mode 100644 test-data/graphs/customer-service-escalation.json create mode 100644 test-data/graphs/delivery-route-optimizer.json create mode 100644 test-data/graphs/device-compatibility-checker.json create mode 100644 test-data/graphs/disaster-relief-fund-allocation.json create mode 100644 test-data/graphs/dynamic-fx-rate-pricing-system.json create mode 100644 test-data/graphs/dynamic-marketplace-comission-calculator.json create mode 100644 test-data/graphs/dynamic-shipping-cost-calculator.json create mode 100644 test-data/graphs/dynamic-tarrif-engine.json create mode 100644 test-data/graphs/dynamic-ticket-pricing.json create mode 100644 test-data/graphs/environment-compliance-assessment.json create mode 100644 test-data/graphs/flash-sale-eligibility.json create mode 100644 test-data/graphs/flight-ancillary-recommendations.json create mode 100644 test-data/graphs/flight-dispatch-decision-system.json create mode 100644 test-data/graphs/flight-rebooking-fee-calculator.json create mode 100644 test-data/graphs/government-assistance.json create mode 100644 test-data/graphs/grant-funding-distribution.json create mode 100644 test-data/graphs/hazardous-materials-management-system.json create mode 100644 test-data/graphs/immigration-eligibility-evaluator.json create mode 100644 test-data/graphs/import-duties-calculator.json create mode 100644 test-data/graphs/insurance-agent-commission.json create mode 100644 test-data/graphs/insurance-coverage-calculator.json create mode 100644 test-data/graphs/insurance-prior-authorization.json create mode 100644 test-data/graphs/insurance-underwriting-risk.json create mode 100644 test-data/graphs/international-roaming-policy-manager.json create mode 100644 test-data/graphs/last-mile-delivery-assignment.json create mode 100644 test-data/graphs/legacy-plan-management.json create mode 100644 test-data/graphs/loan-approval.json create mode 100644 test-data/graphs/marketplace-listing-verification-system.json create mode 100644 test-data/graphs/marketplace-seller-grading-system.json create mode 100644 test-data/graphs/medical-appointment-priority-system.json create mode 100644 test-data/graphs/medication-dosage-calculator.json create mode 100644 test-data/graphs/municipal-permit-evaluation-system.json create mode 100644 test-data/graphs/mvno-partner-enablement.json create mode 100644 test-data/graphs/online-checkin-eligibility.json create mode 100644 test-data/graphs/order-consolidation-system.json create mode 100644 test-data/graphs/partner-revenue-sharing.json create mode 100644 test-data/graphs/patient-triage-system.json create mode 100644 test-data/graphs/payment-routing-and-fee-calculator.json create mode 100644 test-data/graphs/policy-discount-calculator.json create mode 100644 test-data/graphs/policy-eligibility-analyzer.json create mode 100644 test-data/graphs/portfolio-risk-monitor.json create mode 100644 test-data/graphs/preventive-care-recommendation.json create mode 100644 test-data/graphs/product-listing-scoring.json create mode 100644 test-data/graphs/realtime-fraud-detection.json create mode 100644 test-data/graphs/regional-compliance-manager.json create mode 100644 test-data/graphs/returns-and-refund-policy.json create mode 100644 test-data/graphs/returns-processing-system.json create mode 100644 test-data/graphs/school-district-resource-allocation.json create mode 100644 test-data/graphs/seat-map-optimization.json create mode 100644 test-data/graphs/seller-approval-workflow.json create mode 100644 test-data/graphs/seller-fee-calculator.json create mode 100644 test-data/graphs/service-level-agreement-enforcement.json create mode 100644 test-data/graphs/shipping-carrier-selector.json create mode 100644 test-data/graphs/smart-financial-product-matcher.json create mode 100644 test-data/graphs/supply-chain-risk.json create mode 100644 test-data/graphs/tax-exemption.json create mode 100644 test-data/graphs/traffic-violation-penalty-calculator.json create mode 100644 test-data/graphs/transaction-compliance-classifier.json create mode 100644 test-data/graphs/vehicle-claims-resolution.json create mode 100644 test-data/graphs/warehouse-cross-docking.json create mode 100644 test-data/graphs/warehouse-storage-location.json diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 66bea3da..49928701 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -31,6 +31,7 @@ zen-tmpl = { path = "../template", version = "0.49.1" } [dev-dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } criterion = { workspace = true, features = ["async_tokio"] } +insta = { version = "1.43", features = ["yaml", "redactions"] } [[bench]] harness = false diff --git a/core/engine/tests/engine.rs b/core/engine/tests/engine.rs index c0337dff..e8997bd9 100644 --- a/core/engine/tests/engine.rs +++ b/core/engine/tests/engine.rs @@ -264,6 +264,64 @@ async fn engine_graph_tests() { } } +#[tokio::test] +#[cfg_attr(miri, ignore)] +async fn engine_snapshot_tests() { + #[derive(Deserialize)] + #[serde(rename_all = "camelCase")] + struct TestCase { + input: Variable, + output: Variable, + } + + #[derive(Deserialize)] + #[serde(rename_all = "camelCase")] + struct TestData { + tests: Vec, + #[serde(flatten)] + decision_content: DecisionContent, + } + + let engine = DecisionEngine::default(); + + let graphs_path = Path::new(test_data_root().as_str()).join("graphs"); + let file_list = fs::read_dir(graphs_path).unwrap(); + for maybe_file in file_list { + let Ok(file) = maybe_file else { + panic!("Failed to read DirEntry {maybe_file:?}"); + }; + + let file_name = file.file_name().to_str().map(|s| s.to_string()).unwrap(); + let file_name = if let Some(pos) = file_name.rfind('.') { + file_name[..pos].to_string() + } else { + file_name + }; + let file_contents = fs::read_to_string(file.path()).expect("valid file data"); + let test_data: TestData = serde_json::from_str(&file_contents).expect("Valid JSON"); + + let decision = engine.create_decision(test_data.decision_content.into()); + for (index, test_case) in test_data.tests.iter().enumerate() { + let input = test_case.input.clone(); + let result = decision + .evaluate_with_opts( + input.clone(), + EvaluationOptions { + trace: Some(true), + max_depth: None, + }, + ) + .await + .unwrap(); + let serialized_result = serde_json::to_value(&result).unwrap(); + insta::assert_yaml_snapshot!(format!("{}_{}", file_name, index), serialized_result, { + ".performance" => "[perf]", + ".trace.*.performance" => "[perf]" + }); + } + } +} + #[tokio::test] #[cfg_attr(miri, ignore)] async fn engine_function_v2() { diff --git a/core/engine/tests/snapshots/.gitignore b/core/engine/tests/snapshots/.gitignore new file mode 100644 index 00000000..eebafe8c --- /dev/null +++ b/core/engine/tests/snapshots/.gitignore @@ -0,0 +1 @@ +*.new \ No newline at end of file diff --git a/core/engine/tests/snapshots/engine__account-dormancy-management_0.snap b/core/engine/tests/snapshots/engine__account-dormancy-management_0.snap new file mode 100644 index 00000000..4b1abeae --- /dev/null +++ b/core/engine/tests/snapshots/engine__account-dormancy-management_0.snap @@ -0,0 +1,219 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + actionPriority: high + recommendedAction: fee_waiver +trace: + dt1: + id: dt1 + input: + accountBalance: + "$serde_json::private::Number": "25750.45" + accountId: ACC98765432 + accountType: savings + contactPreference: email + currency: USD + customerEmail: customer@example.com + customerPhone: "+15551234567" + customerTier: premium + daysSinceLastActivity: + "$serde_json::private::Number": "24054457" + daysToThreshold: + "$serde_json::private::Number": "-24054277" + dormancyThreshold: + "$serde_json::private::Number": "180" + lastActivityDate: 2024-11-15 + region: NORTH_AMERICA + regulatoryJurisdiction: US-NY + name: dormancy_status + order: + "$serde_json::private::Number": "2" + output: + accountBalance: + "$serde_json::private::Number": "25750.45" + accountId: ACC98765432 + accountType: savings + contactPreference: email + currency: USD + customerEmail: customer@example.com + customerPhone: "+15551234567" + customerTier: premium + daysSinceLastActivity: + "$serde_json::private::Number": "24054457" + daysToThreshold: + "$serde_json::private::Number": "-24054277" + dormancyStatus: dormant + dormancyThreshold: + "$serde_json::private::Number": "180" + lastActivityDate: 2024-11-15 + region: NORTH_AMERICA + regulatoryJurisdiction: US-NY + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + daysToThreshold: + "$serde_json::private::Number": "-24054277" + rule: + _id: r1-1 + "daysToThreshold[i1-1]": "< 0" + dt2: + id: dt2 + input: + accountBalance: + "$serde_json::private::Number": "25750.45" + accountId: ACC98765432 + accountType: savings + contactPreference: email + currency: USD + customerEmail: customer@example.com + customerPhone: "+15551234567" + customerTier: premium + daysSinceLastActivity: + "$serde_json::private::Number": "24054457" + daysToThreshold: + "$serde_json::private::Number": "-24054277" + dormancyStatus: dormant + dormancyThreshold: + "$serde_json::private::Number": "180" + lastActivityDate: 2024-11-15 + region: NORTH_AMERICA + regulatoryJurisdiction: US-NY + name: determine_action + order: + "$serde_json::private::Number": "4" + output: + actionPriority: high + recommendedAction: fee_waiver + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + customerTier: premium + dormancyStatus: dormant + rule: + _id: r2-1 + "customerTier[i2-2]": "'premium'" + "dormancyStatus[i2-1]": "'dormant'" + ex1: + id: ex1 + input: + accountBalance: + "$serde_json::private::Number": "25750.45" + accountId: ACC98765432 + accountType: savings + contactPreference: email + currency: USD + customerEmail: customer@example.com + customerPhone: "+15551234567" + customerTier: premium + dormancyThreshold: + "$serde_json::private::Number": "180" + lastActivityDate: 2024-11-15 + region: NORTH_AMERICA + regulatoryJurisdiction: US-NY + name: calculate_dormancy + order: + "$serde_json::private::Number": "1" + output: + accountBalance: + "$serde_json::private::Number": "25750.45" + accountId: ACC98765432 + accountType: savings + contactPreference: email + currency: USD + customerEmail: customer@example.com + customerPhone: "+15551234567" + customerTier: premium + daysSinceLastActivity: + "$serde_json::private::Number": "24054457" + daysToThreshold: + "$serde_json::private::Number": "-24054277" + dormancyThreshold: + "$serde_json::private::Number": "180" + lastActivityDate: 2024-11-15 + region: NORTH_AMERICA + regulatoryJurisdiction: US-NY + performance: "[perf]" + traceData: + daysSinceLastActivity: + result: "24054457" + daysToThreshold: + result: "-24054277" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + accountBalance: + "$serde_json::private::Number": "25750.45" + accountId: ACC98765432 + accountType: savings + contactPreference: email + currency: USD + customerEmail: customer@example.com + customerPhone: "+15551234567" + customerTier: premium + dormancyThreshold: + "$serde_json::private::Number": "180" + lastActivityDate: 2024-11-15 + region: NORTH_AMERICA + regulatoryJurisdiction: US-NY + performance: "[perf]" + traceData: ~ + sw1: + id: sw1 + input: + accountBalance: + "$serde_json::private::Number": "25750.45" + accountId: ACC98765432 + accountType: savings + contactPreference: email + currency: USD + customerEmail: customer@example.com + customerPhone: "+15551234567" + customerTier: premium + daysSinceLastActivity: + "$serde_json::private::Number": "24054457" + daysToThreshold: + "$serde_json::private::Number": "-24054277" + dormancyStatus: dormant + dormancyThreshold: + "$serde_json::private::Number": "180" + lastActivityDate: 2024-11-15 + region: NORTH_AMERICA + regulatoryJurisdiction: US-NY + name: route_by_status + order: + "$serde_json::private::Number": "3" + output: + accountBalance: + "$serde_json::private::Number": "25750.45" + accountId: ACC98765432 + accountType: savings + contactPreference: email + currency: USD + customerEmail: customer@example.com + customerPhone: "+15551234567" + customerTier: premium + daysSinceLastActivity: + "$serde_json::private::Number": "24054457" + daysToThreshold: + "$serde_json::private::Number": "-24054277" + dormancyStatus: dormant + dormancyThreshold: + "$serde_json::private::Number": "180" + lastActivityDate: 2024-11-15 + region: NORTH_AMERICA + regulatoryJurisdiction: US-NY + performance: "[perf]" + traceData: + statements: + - id: s1-1 diff --git a/core/engine/tests/snapshots/engine__affiliate-commission-calculator_0.snap b/core/engine/tests/snapshots/engine__affiliate-commission-calculator_0.snap new file mode 100644 index 00000000..50450b2c --- /dev/null +++ b/core/engine/tests/snapshots/engine__affiliate-commission-calculator_0.snap @@ -0,0 +1,151 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + commissionAmount: + "$serde_json::private::Number": "69.3" + finalCommissionRate: + "$serde_json::private::Number": "0.198" + promotionMultiplier: + "$serde_json::private::Number": "1.25" +trace: + dt1: + id: dt1 + input: + conversionRate: + "$serde_json::private::Number": "0.12" + isSpecialPromotion: true + monthlyReferrals: + "$serde_json::private::Number": "75" + productCategory: fashion + saleAmount: + "$serde_json::private::Number": "350" + name: categoryRates + order: + "$serde_json::private::Number": "1" + output: + baseCommissionRate: + "$serde_json::private::Number": "0.12" + conversionRate: + "$serde_json::private::Number": "0.12" + isSpecialPromotion: true + monthlyReferrals: + "$serde_json::private::Number": "75" + productCategory: fashion + saleAmount: + "$serde_json::private::Number": "350" + volumeBonusMax: + "$serde_json::private::Number": "0.04" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + productCategory: fashion + rule: + _id: r1-2 + "productCategory[i1-1]": "'fashion'" + dt2: + id: dt2 + input: + baseCommissionRate: + "$serde_json::private::Number": "0.12" + conversionRate: + "$serde_json::private::Number": "0.12" + isSpecialPromotion: true + monthlyReferrals: + "$serde_json::private::Number": "75" + productCategory: fashion + saleAmount: + "$serde_json::private::Number": "350" + volumeBonusMax: + "$serde_json::private::Number": "0.04" + name: performanceRates + order: + "$serde_json::private::Number": "2" + output: + baseCommissionRate: + "$serde_json::private::Number": "0.12" + conversionRate: + "$serde_json::private::Number": "0.12" + isSpecialPromotion: true + monthlyReferrals: + "$serde_json::private::Number": "75" + performanceMultiplier: + "$serde_json::private::Number": "1.1" + productCategory: fashion + saleAmount: + "$serde_json::private::Number": "350" + volumeBonus: + "$serde_json::private::Number": "0.024" + volumeBonusMax: + "$serde_json::private::Number": "0.04" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + conversionRate: + "$serde_json::private::Number": "0.12" + monthlyReferrals: + "$serde_json::private::Number": "75" + rule: + _id: r2-3 + "conversionRate[i2-2]": ">= 0.10" + "monthlyReferrals[i2-1]": ">= 50" + ex1: + id: ex1 + input: + baseCommissionRate: + "$serde_json::private::Number": "0.12" + conversionRate: + "$serde_json::private::Number": "0.12" + isSpecialPromotion: true + monthlyReferrals: + "$serde_json::private::Number": "75" + performanceMultiplier: + "$serde_json::private::Number": "1.1" + productCategory: fashion + saleAmount: + "$serde_json::private::Number": "350" + volumeBonus: + "$serde_json::private::Number": "0.024" + volumeBonusMax: + "$serde_json::private::Number": "0.04" + name: calculateCommission + order: + "$serde_json::private::Number": "3" + output: + commissionAmount: + "$serde_json::private::Number": "69.3" + finalCommissionRate: + "$serde_json::private::Number": "0.198" + promotionMultiplier: + "$serde_json::private::Number": "1.25" + performance: "[perf]" + traceData: + commissionAmount: + result: "69.3" + finalCommissionRate: + result: "0.198" + promotionMultiplier: + result: "1.25" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + conversionRate: + "$serde_json::private::Number": "0.12" + isSpecialPromotion: true + monthlyReferrals: + "$serde_json::private::Number": "75" + productCategory: fashion + saleAmount: + "$serde_json::private::Number": "350" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__airline-loyalty-points-calculations_0.snap b/core/engine/tests/snapshots/engine__airline-loyalty-points-calculations_0.snap new file mode 100644 index 00000000..25c37299 --- /dev/null +++ b/core/engine/tests/snapshots/engine__airline-loyalty-points-calculations_0.snap @@ -0,0 +1,212 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + calculatedPoints: + "$serde_json::private::Number": "9000" + seasonalPromotion: + "$serde_json::private::Number": "1.5" + totalPoints: + "$serde_json::private::Number": "9000" +trace: + dt1: + id: dt1 + input: + booking: + distance: + "$serde_json::private::Number": "3500" + fareClass: Business + isSeasonalPromotion: true + routeType: International + member: + enrollmentDate: 2020-05-15 + id: MEM12345 + name: John Smith + status: Gold + name: fareClassMultiplier + order: + "$serde_json::private::Number": "1" + output: + booking: + distance: + "$serde_json::private::Number": "3500" + fareClass: Business + isSeasonalPromotion: true + routeType: International + member: + enrollmentDate: 2020-05-15 + id: MEM12345 + name: John Smith + status: Gold + points: + fareMultiplier: + "$serde_json::private::Number": "2" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + booking.fareClass: Business + rule: + _id: r1-2 + "booking.fareClass[i1-1]": "'Business'" + dt2: + id: dt2 + input: + booking: + distance: + "$serde_json::private::Number": "3500" + fareClass: Business + isSeasonalPromotion: true + routeType: International + member: + enrollmentDate: 2020-05-15 + id: MEM12345 + name: John Smith + status: Gold + points: + fareMultiplier: + "$serde_json::private::Number": "2" + name: routeBasePoints + order: + "$serde_json::private::Number": "2" + output: + booking: + distance: + "$serde_json::private::Number": "3500" + fareClass: Business + isSeasonalPromotion: true + routeType: International + member: + enrollmentDate: 2020-05-15 + id: MEM12345 + name: John Smith + status: Gold + points: + basePoints: + "$serde_json::private::Number": "2000" + fareMultiplier: + "$serde_json::private::Number": "2" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + booking.distance: + "$serde_json::private::Number": "3500" + booking.routeType: International + rule: + _id: r2-5 + "booking.distance[i2-2]": "[2000..5000]" + "booking.routeType[i2-1]": "'International'" + dt3: + id: dt3 + input: + booking: + distance: + "$serde_json::private::Number": "3500" + fareClass: Business + isSeasonalPromotion: true + routeType: International + member: + enrollmentDate: 2020-05-15 + id: MEM12345 + name: John Smith + status: Gold + points: + basePoints: + "$serde_json::private::Number": "2000" + fareMultiplier: + "$serde_json::private::Number": "2" + name: memberStatusMultiplier + order: + "$serde_json::private::Number": "3" + output: + booking: + distance: + "$serde_json::private::Number": "3500" + fareClass: Business + isSeasonalPromotion: true + routeType: International + member: + enrollmentDate: 2020-05-15 + id: MEM12345 + name: John Smith + status: Gold + points: + basePoints: + "$serde_json::private::Number": "2000" + fareMultiplier: + "$serde_json::private::Number": "2" + statusMultiplier: + "$serde_json::private::Number": "1.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + member.status: Gold + rule: + _id: r3-2 + "member.status[i3-1]": "'Gold'" + ex1: + id: ex1 + input: + booking: + distance: + "$serde_json::private::Number": "3500" + fareClass: Business + isSeasonalPromotion: true + routeType: International + member: + enrollmentDate: 2020-05-15 + id: MEM12345 + name: John Smith + status: Gold + points: + basePoints: + "$serde_json::private::Number": "2000" + fareMultiplier: + "$serde_json::private::Number": "2" + statusMultiplier: + "$serde_json::private::Number": "1.5" + name: calculateTotalPoints + order: + "$serde_json::private::Number": "4" + output: + calculatedPoints: + "$serde_json::private::Number": "9000" + seasonalPromotion: + "$serde_json::private::Number": "1.5" + totalPoints: + "$serde_json::private::Number": "9000" + performance: "[perf]" + traceData: + calculatedPoints: + result: "9000" + seasonalPromotion: + result: "1.5" + totalPoints: + result: "9000" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + booking: + distance: + "$serde_json::private::Number": "3500" + fareClass: Business + isSeasonalPromotion: true + routeType: International + member: + enrollmentDate: 2020-05-15 + id: MEM12345 + name: John Smith + status: Gold + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__airline-upgrade-eligibility_0.snap b/core/engine/tests/snapshots/engine__airline-upgrade-eligibility_0.snap new file mode 100644 index 00000000..d558cf80 --- /dev/null +++ b/core/engine/tests/snapshots/engine__airline-upgrade-eligibility_0.snap @@ -0,0 +1,450 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + result: + isEligible: false + reason: Check-in not completed + score: + "$serde_json::private::Number": "0" +trace: + calculateFareScore: + id: calculateFareScore + input: + basicEligibility: + isEligible: false + reason: Check-in not completed + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + scores: + loyalty: + "$serde_json::private::Number": "35" + name: calculateFareScore + order: + "$serde_json::private::Number": "3" + output: + basicEligibility: + isEligible: false + reason: Check-in not completed + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + scores: + fare: + "$serde_json::private::Number": "20" + loyalty: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + passenger.fareClass: premium economy + rule: + _id: rule2 + "passenger.fareClass[i3-1]": "'premium economy'" + calculateLoyaltyScore: + id: calculateLoyaltyScore + input: + basicEligibility: + isEligible: false + reason: Check-in not completed + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + name: calculateLoyaltyScore + order: + "$serde_json::private::Number": "2" + output: + basicEligibility: + isEligible: false + reason: Check-in not completed + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + scores: + loyalty: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + passenger.loyaltyMiles: + "$serde_json::private::Number": "82500" + passenger.loyaltyStatus: gold + rule: + _id: rule3 + "passenger.loyaltyMiles[i2-2]": "> 75000" + "passenger.loyaltyStatus[i2-1]": "'gold'" + checkBasicEligibility: + id: checkBasicEligibility + input: + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + name: checkBasicEligibility + order: + "$serde_json::private::Number": "1" + output: + basicEligibility: + isEligible: false + reason: Check-in not completed + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + passenger.ticketStatus: confirmed + rule: + _id: rule3 + "passenger.ticketStatus[i1-1]": "!= 'completed'" + checkCorporateAgreement: + id: checkCorporateAgreement + input: + basicEligibility: + isEligible: false + reason: Check-in not completed + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + scores: + fare: + "$serde_json::private::Number": "20" + loyalty: + "$serde_json::private::Number": "35" + name: checkCorporateAgreement + order: + "$serde_json::private::Number": "4" + output: + basicEligibility: + isEligible: false + reason: Check-in not completed + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + scores: + corporate: + "$serde_json::private::Number": "25" + fare: + "$serde_json::private::Number": "20" + loyalty: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + corporate.agreementLevel: premier + corporate.upgradeEligible: true + rule: + _id: rule1 + "corporate.agreementLevel[i4-1]": "'premier'" + "corporate.upgradeEligible[i4-2]": "true" + determineUpgradeEligibility: + id: determineUpgradeEligibility + input: + basicEligibility: + isEligible: false + reason: Check-in not completed + cabinMultiplier: + "$serde_json::private::Number": "1" + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + finalScore: + "$serde_json::private::Number": "80" + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + scores: + corporate: + "$serde_json::private::Number": "25" + fare: + "$serde_json::private::Number": "20" + loyalty: + "$serde_json::private::Number": "35" + totalScore: + "$serde_json::private::Number": "80" + name: determineUpgradeEligibility + order: + "$serde_json::private::Number": "6" + output: + result: + isEligible: false + reason: Check-in not completed + score: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: rule1 + evaluateCabinAvailability: + id: evaluateCabinAvailability + input: + basicEligibility: + isEligible: false + reason: Check-in not completed + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + scores: + corporate: + "$serde_json::private::Number": "25" + fare: + "$serde_json::private::Number": "20" + loyalty: + "$serde_json::private::Number": "35" + name: evaluateCabinAvailability + order: + "$serde_json::private::Number": "5" + output: + basicEligibility: + isEligible: false + reason: Check-in not completed + cabinMultiplier: + "$serde_json::private::Number": "1" + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + finalScore: + "$serde_json::private::Number": "80" + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + scores: + corporate: + "$serde_json::private::Number": "25" + fare: + "$serde_json::private::Number": "20" + loyalty: + "$serde_json::private::Number": "35" + totalScore: + "$serde_json::private::Number": "80" + performance: "[perf]" + traceData: + cabinMultiplier: + result: "1" + finalScore: + result: "80" + totalScore: + result: "80" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + corporate: + agreementLevel: premier + companyName: Acme Corporation + upgradeEligible: true + flight: + cabinAvailability: + "$serde_json::private::Number": "7" + departureDate: 2025-04-15 + flightNumber: FL789 + route: LHR-JFK + passenger: + checkInStatus: completed + fareClass: premium economy + flightStatus: scheduled + id: P123456 + loyaltyMiles: + "$serde_json::private::Number": "82500" + loyaltyStatus: gold + name: Jane Smith + ticketStatus: confirmed + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__aml_0.snap b/core/engine/tests/snapshots/engine__aml_0.snap new file mode 100644 index 00000000..0260d1e9 --- /dev/null +++ b/core/engine/tests/snapshots/engine__aml_0.snap @@ -0,0 +1,347 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breakdown: + amber: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "3" + red: + "$serde_json::private::Number": "1" + flags: + eurSanctions: red + globalSanctions: green + merchantReputation: green + transactionAmount: green + overallFlag: red +trace: + 204af8f6-325f-41cc-a5bd-ee99905d8c1f: + id: 204af8f6-325f-41cc-a5bd-ee99905d8c1f + input: + flags: + eurSanctions: red + globalSanctions: green + merchantReputation: green + transactionAmount: green + name: Aggregator + order: + "$serde_json::private::Number": "6" + output: + breakdown: + amber: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "3" + red: + "$serde_json::private::Number": "1" + flags: + eurSanctions: red + globalSanctions: green + merchantReputation: green + transactionAmount: green + overallFlag: red + performance: "[perf]" + traceData: + log: [] + 3187c4af-565f-482c-805f-9099e9d56fc1: + id: 3187c4af-565f-482c-805f-9099e9d56fc1 + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + country: RU + name: SuperMart + reputation: + "$serde_json::private::Number": "0.81" + transaction: + amountUSD: + "$serde_json::private::Number": "100.5" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: EUR Sanctions + order: + "$serde_json::private::Number": "2" + output: + flags: + eurSanctions: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + merchant.location.country: RU + rule: + _id: ff990579-78ff-4a25-9706-eae402a26c4e + "merchant.location.country[90adfc05-ffdf-490f-ab47-cede8dd899f3]": "\"RU\", \"NK\"" + 57b828f3-e0ff-4e3a-9549-7dae4eeba55d: + id: 57b828f3-e0ff-4e3a-9549-7dae4eeba55d + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + country: RU + name: SuperMart + reputation: + "$serde_json::private::Number": "0.81" + transaction: + amountUSD: + "$serde_json::private::Number": "100.5" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Merchant Reputation + order: + "$serde_json::private::Number": "5" + output: + flags: + merchantReputation: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + merchant.reputation: + "$serde_json::private::Number": "0.81" + rule: + _id: e8a05a05-d7f7-4272-94a1-c5aa84b0feaf + "merchant.reputation[c658ae97-99c8-46fe-bc3a-64c14ea8c475]": "(0.8..1.0]" + 71285ae0-45cf-4300-afe7-de39e0f81590: + id: 71285ae0-45cf-4300-afe7-de39e0f81590 + input: + breakdown: + amber: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "3" + red: + "$serde_json::private::Number": "1" + flags: + eurSanctions: red + globalSanctions: green + merchantReputation: green + transactionAmount: green + overallFlag: red + name: Response + order: + "$serde_json::private::Number": "7" + output: ~ + performance: "[perf]" + traceData: ~ + ac9cf968-98b2-4ba5-a481-28da1e32b649: + id: ac9cf968-98b2-4ba5-a481-28da1e32b649 + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + country: RU + name: SuperMart + reputation: + "$serde_json::private::Number": "0.81" + transaction: + amountUSD: + "$serde_json::private::Number": "100.5" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Transaction Amount + order: + "$serde_json::private::Number": "4" + output: + flags: + transactionAmount: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "7" + reference_map: + customer.tier: ~ + transaction.amountUSD: + "$serde_json::private::Number": "100.5" + rule: + _id: 58cf804e-ad94-4ed6-99fe-8263ae8cf7cd + "customer.tier[a713c7ef-1db6-4fa4-aca4-590c4092c742]": "" + "transaction.amountUSD[360ba5d7-25b0-44ff-9cce-3f365634a42f]": "" + df092198-208d-4526-82a2-2ff4359d9001: + id: df092198-208d-4526-82a2-2ff4359d9001 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + country: RU + name: SuperMart + reputation: + "$serde_json::private::Number": "0.81" + transaction: + amountUSD: + "$serde_json::private::Number": "100.5" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + performance: "[perf]" + traceData: ~ + f7e19179-48b7-4d94-b085-ea3d6c9e829e: + id: f7e19179-48b7-4d94-b085-ea3d6c9e829e + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + country: RU + name: SuperMart + reputation: + "$serde_json::private::Number": "0.81" + transaction: + amountUSD: + "$serde_json::private::Number": "100.5" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Sanctions + order: + "$serde_json::private::Number": "1" + output: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + country: RU + name: SuperMart + reputation: + "$serde_json::private::Number": "0.81" + transaction: + amountUSD: + "$serde_json::private::Number": "100.5" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + performance: "[perf]" + traceData: + statements: + - id: 13737427-cb8c-4c32-bde5-e49ef6fa03e0 + - id: aa630466-3bb1-45e3-9ae8-12eb57451f55 + fd8f6200-f236-4d00-859e-9a732e553176: + id: fd8f6200-f236-4d00-859e-9a732e553176 + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + country: RU + name: SuperMart + reputation: + "$serde_json::private::Number": "0.81" + transaction: + amountUSD: + "$serde_json::private::Number": "100.5" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Global Sanctions + order: + "$serde_json::private::Number": "3" + output: + flags: + globalSanctions: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: 380eee74-94aa-4321-a673-878386dc3200 diff --git a/core/engine/tests/snapshots/engine__aml_1.snap b/core/engine/tests/snapshots/engine__aml_1.snap new file mode 100644 index 00000000..c504e9ba --- /dev/null +++ b/core/engine/tests/snapshots/engine__aml_1.snap @@ -0,0 +1,375 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breakdown: + amber: + "$serde_json::private::Number": "2" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "0" + flags: + globalSanctions: green + merchantReputation: amber + transactionAmount: amber + usdSanction: green + overallFlag: amber +trace: + 204af8f6-325f-41cc-a5bd-ee99905d8c1f: + id: 204af8f6-325f-41cc-a5bd-ee99905d8c1f + input: + flags: + globalSanctions: green + merchantReputation: amber + transactionAmount: amber + usdSanction: green + name: Aggregator + order: + "$serde_json::private::Number": "6" + output: + breakdown: + amber: + "$serde_json::private::Number": "2" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "0" + flags: + globalSanctions: green + merchantReputation: amber + transactionAmount: amber + usdSanction: green + overallFlag: amber + performance: "[perf]" + traceData: + log: [] + 57b828f3-e0ff-4e3a-9549-7dae4eeba55d: + id: 57b828f3-e0ff-4e3a-9549-7dae4eeba55d + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: USA + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000.5" + currency: USD + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Merchant Reputation + order: + "$serde_json::private::Number": "5" + output: + flags: + merchantReputation: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + merchant.reputation: + "$serde_json::private::Number": "0.55" + rule: + _id: cdee900f-a1b1-4a0c-8aca-c305c19a33dd + "merchant.reputation[c658ae97-99c8-46fe-bc3a-64c14ea8c475]": "(0.5..0.8]" + 71285ae0-45cf-4300-afe7-de39e0f81590: + id: 71285ae0-45cf-4300-afe7-de39e0f81590 + input: + breakdown: + amber: + "$serde_json::private::Number": "2" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "0" + flags: + globalSanctions: green + merchantReputation: amber + transactionAmount: amber + usdSanction: green + overallFlag: amber + name: Response + order: + "$serde_json::private::Number": "7" + output: ~ + performance: "[perf]" + traceData: ~ + 9bc09d87-84ce-4f4c-9c53-317688ee6cc5: + id: 9bc09d87-84ce-4f4c-9c53-317688ee6cc5 + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: USA + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000.5" + currency: USD + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: USD Sanctions + order: + "$serde_json::private::Number": "2" + output: + flags: + usdSanction: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + merchant.location.country: USA + rule: + _id: 26b794b7-26ce-4e51-9432-cf1d3580a638 + "merchant.location.country[e03b1f07-7d3a-4a64-9aa5-aca83e4cfa01]": "" + ac9cf968-98b2-4ba5-a481-28da1e32b649: + id: ac9cf968-98b2-4ba5-a481-28da1e32b649 + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: USA + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000.5" + currency: USD + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Transaction Amount + order: + "$serde_json::private::Number": "4" + output: + flags: + transactionAmount: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "6" + reference_map: + customer.tier: ~ + transaction.amountUSD: + "$serde_json::private::Number": "30000.5" + rule: + _id: 65f91c4f-bf69-40fa-86c6-36ad71abbc1b + "customer.tier[a713c7ef-1db6-4fa4-aca4-590c4092c742]": "" + "transaction.amountUSD[360ba5d7-25b0-44ff-9cce-3f365634a42f]": "> 10_000" + df092198-208d-4526-82a2-2ff4359d9001: + id: df092198-208d-4526-82a2-2ff4359d9001 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: USA + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000.5" + currency: USD + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + performance: "[perf]" + traceData: ~ + f7e19179-48b7-4d94-b085-ea3d6c9e829e: + id: f7e19179-48b7-4d94-b085-ea3d6c9e829e + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: USA + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000.5" + currency: USD + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Sanctions + order: + "$serde_json::private::Number": "1" + output: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: USA + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000.5" + currency: USD + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + performance: "[perf]" + traceData: + statements: + - id: 5bffb0f5-a69d-46ba-9122-08bae9f6fe92 + - id: aa630466-3bb1-45e3-9ae8-12eb57451f55 + fd8f6200-f236-4d00-859e-9a732e553176: + id: fd8f6200-f236-4d00-859e-9a732e553176 + input: + customer: + address: + city: Anytown + country: USA + state: CA + street: 123 Main St + zipCode: "12345" + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: USA + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000.5" + currency: USD + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Global Sanctions + order: + "$serde_json::private::Number": "3" + output: + flags: + globalSanctions: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: 380eee74-94aa-4321-a673-878386dc3200 diff --git a/core/engine/tests/snapshots/engine__aml_2.snap b/core/engine/tests/snapshots/engine__aml_2.snap new file mode 100644 index 00000000..66e6a76a --- /dev/null +++ b/core/engine/tests/snapshots/engine__aml_2.snap @@ -0,0 +1,354 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breakdown: + amber: + "$serde_json::private::Number": "2" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "0" + flags: + eurSanctions: amber + globalSanctions: green + merchantReputation: amber + transactionAmount: green + overallFlag: amber +trace: + 204af8f6-325f-41cc-a5bd-ee99905d8c1f: + id: 204af8f6-325f-41cc-a5bd-ee99905d8c1f + input: + flags: + eurSanctions: amber + globalSanctions: green + merchantReputation: amber + transactionAmount: green + name: Aggregator + order: + "$serde_json::private::Number": "6" + output: + breakdown: + amber: + "$serde_json::private::Number": "2" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "0" + flags: + eurSanctions: amber + globalSanctions: green + merchantReputation: amber + transactionAmount: green + overallFlag: amber + performance: "[perf]" + traceData: + log: [] + 3187c4af-565f-482c-805f-9099e9d56fc1: + id: 3187c4af-565f-482c-805f-9099e9d56fc1 + input: + customer: + address: + country: FR + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + tier: enterprise + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: VE + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: EUR Sanctions + order: + "$serde_json::private::Number": "2" + output: + flags: + eurSanctions: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + merchant.location.country: VE + rule: + _id: 380670ff-4a6a-48d6-b430-8cbb6186438b + "merchant.location.country[90adfc05-ffdf-490f-ab47-cede8dd899f3]": "\"VE\", \"IR\"" + 57b828f3-e0ff-4e3a-9549-7dae4eeba55d: + id: 57b828f3-e0ff-4e3a-9549-7dae4eeba55d + input: + customer: + address: + country: FR + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + tier: enterprise + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: VE + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Merchant Reputation + order: + "$serde_json::private::Number": "5" + output: + flags: + merchantReputation: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + merchant.reputation: + "$serde_json::private::Number": "0.55" + rule: + _id: cdee900f-a1b1-4a0c-8aca-c305c19a33dd + "merchant.reputation[c658ae97-99c8-46fe-bc3a-64c14ea8c475]": "(0.5..0.8]" + 71285ae0-45cf-4300-afe7-de39e0f81590: + id: 71285ae0-45cf-4300-afe7-de39e0f81590 + input: + breakdown: + amber: + "$serde_json::private::Number": "2" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "0" + flags: + eurSanctions: amber + globalSanctions: green + merchantReputation: amber + transactionAmount: green + overallFlag: amber + name: Response + order: + "$serde_json::private::Number": "7" + output: ~ + performance: "[perf]" + traceData: ~ + ac9cf968-98b2-4ba5-a481-28da1e32b649: + id: ac9cf968-98b2-4ba5-a481-28da1e32b649 + input: + customer: + address: + country: FR + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + tier: enterprise + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: VE + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Transaction Amount + order: + "$serde_json::private::Number": "4" + output: + flags: + transactionAmount: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + customer.tier: enterprise + transaction.amountUSD: + "$serde_json::private::Number": "30000" + rule: + _id: 831b4587-4f1b-494c-97c3-da2861991779 + "customer.tier[a713c7ef-1db6-4fa4-aca4-590c4092c742]": "\"enterprise\"" + "transaction.amountUSD[360ba5d7-25b0-44ff-9cce-3f365634a42f]": "" + df092198-208d-4526-82a2-2ff4359d9001: + id: df092198-208d-4526-82a2-2ff4359d9001 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + customer: + address: + country: FR + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + tier: enterprise + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: VE + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + performance: "[perf]" + traceData: ~ + f7e19179-48b7-4d94-b085-ea3d6c9e829e: + id: f7e19179-48b7-4d94-b085-ea3d6c9e829e + input: + customer: + address: + country: FR + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + tier: enterprise + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: VE + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Sanctions + order: + "$serde_json::private::Number": "1" + output: + customer: + address: + country: FR + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + tier: enterprise + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: VE + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + performance: "[perf]" + traceData: + statements: + - id: 13737427-cb8c-4c32-bde5-e49ef6fa03e0 + - id: aa630466-3bb1-45e3-9ae8-12eb57451f55 + fd8f6200-f236-4d00-859e-9a732e553176: + id: fd8f6200-f236-4d00-859e-9a732e553176 + input: + customer: + address: + country: FR + email: john.doe@example.com + firstName: John + id: "987654321" + lastName: Doe + tier: enterprise + merchant: + category: Retail + id: "567890123" + location: + city: AnotherTown + country: VE + state: CA + street: 456 High St + zipCode: "54321" + name: SuperMart + reputation: + "$serde_json::private::Number": "0.55" + transaction: + amountUSD: + "$serde_json::private::Number": "30000" + currency: EUR + id: "123456789" + status: pending + timestamp: "2023-11-30T12:34:56Z" + name: Global Sanctions + order: + "$serde_json::private::Number": "3" + output: + flags: + globalSanctions: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: 380eee74-94aa-4321-a673-878386dc3200 diff --git a/core/engine/tests/snapshots/engine__application-risk-assessment_0.snap b/core/engine/tests/snapshots/engine__application-risk-assessment_0.snap new file mode 100644 index 00000000..6e83a8d5 --- /dev/null +++ b/core/engine/tests/snapshots/engine__application-risk-assessment_0.snap @@ -0,0 +1,441 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + approvalStatus: manual-review + interestRateModifier: + "$serde_json::private::Number": "0" + negativeFactors: [] + negativeFactorsCount: + "$serde_json::private::Number": "0" + riskCategory: medium + scores: + creditHistory: + "$serde_json::private::Number": "20" + debtToIncome: + "$serde_json::private::Number": "15" + incomeStability: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "55" +trace: + calculateRiskScore: + id: calculateRiskScore + input: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + scores: + creditHistory: + "$serde_json::private::Number": "20" + debtToIncome: + "$serde_json::private::Number": "15" + incomeStability: + "$serde_json::private::Number": "20" + name: calculateRiskScore + order: + "$serde_json::private::Number": "4" + output: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + negativeFactors: [] + negativeFactorsCount: + "$serde_json::private::Number": "0" + scores: + creditHistory: + "$serde_json::private::Number": "20" + debtToIncome: + "$serde_json::private::Number": "15" + incomeStability: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "55" + performance: "[perf]" + traceData: + negativeFactors: + result: "[]" + negativeFactorsCount: + result: "0" + totalRiskScore: + result: "55" + classifyRisk: + id: classifyRisk + input: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + negativeFactors: [] + negativeFactorsCount: + "$serde_json::private::Number": "0" + scores: + creditHistory: + "$serde_json::private::Number": "20" + debtToIncome: + "$serde_json::private::Number": "15" + incomeStability: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "55" + name: classifyRisk + order: + "$serde_json::private::Number": "5" + output: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + negativeFactors: [] + negativeFactorsCount: + "$serde_json::private::Number": "0" + scores: + creditHistory: + "$serde_json::private::Number": "20" + debtToIncome: + "$serde_json::private::Number": "15" + incomeStability: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "55" + performance: "[perf]" + traceData: + statements: + - id: s2 + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + performance: "[perf]" + traceData: ~ + mediumRiskAction: + id: mediumRiskAction + input: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + negativeFactors: [] + negativeFactorsCount: + "$serde_json::private::Number": "0" + scores: + creditHistory: + "$serde_json::private::Number": "20" + debtToIncome: + "$serde_json::private::Number": "15" + incomeStability: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "55" + name: mediumRiskAction + order: + "$serde_json::private::Number": "6" + output: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + approvalStatus: manual-review + interestRateModifier: + "$serde_json::private::Number": "0" + negativeFactors: [] + negativeFactorsCount: + "$serde_json::private::Number": "0" + riskCategory: medium + scores: + creditHistory: + "$serde_json::private::Number": "20" + debtToIncome: + "$serde_json::private::Number": "15" + incomeStability: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "55" + performance: "[perf]" + traceData: + approvalStatus: + result: "\"manual-review\"" + interestRateModifier: + result: "0" + riskCategory: + result: "\"medium\"" + scoreCreditHistory: + id: scoreCreditHistory + input: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + name: scoreCreditHistory + order: + "$serde_json::private::Number": "1" + output: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + scores: + creditHistory: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + applicant.creditHistoryMonths: + "$serde_json::private::Number": "48" + applicant.creditScore: + "$serde_json::private::Number": "710" + applicant.latePayments: + "$serde_json::private::Number": "1" + rule: + _id: r1-2 + "applicant.creditHistoryMonths[i1-3]": "> 36" + "applicant.creditScore[i1-1]": "[650..750]" + "applicant.latePayments[i1-2]": "< 4" + scoreDebtToIncome: + id: scoreDebtToIncome + input: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + scores: + creditHistory: + "$serde_json::private::Number": "20" + incomeStability: + "$serde_json::private::Number": "20" + name: scoreDebtToIncome + order: + "$serde_json::private::Number": "3" + output: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + scores: + creditHistory: + "$serde_json::private::Number": "20" + debtToIncome: + "$serde_json::private::Number": "15" + incomeStability: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + applicant.debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + applicant.outstandingLoans: + "$serde_json::private::Number": "2" + rule: + _id: r3-2 + "applicant.debtToIncomeRatio[i3-1]": "< 0.4" + "applicant.outstandingLoans[i3-2]": "< 3" + scoreIncomeStability: + id: scoreIncomeStability + input: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + scores: + creditHistory: + "$serde_json::private::Number": "20" + name: scoreIncomeStability + order: + "$serde_json::private::Number": "2" + output: + applicant: + bankAccountStanding: good + creditHistoryMonths: + "$serde_json::private::Number": "48" + creditScore: + "$serde_json::private::Number": "710" + debtToIncomeRatio: + "$serde_json::private::Number": "0.35" + employmentMonths: + "$serde_json::private::Number": "36" + incomeVerification: complete + latePayments: + "$serde_json::private::Number": "1" + outstandingLoans: + "$serde_json::private::Number": "2" + scores: + creditHistory: + "$serde_json::private::Number": "20" + incomeStability: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + applicant.bankAccountStanding: good + applicant.employmentMonths: + "$serde_json::private::Number": "36" + applicant.incomeVerification: complete + rule: + _id: r2-2 + "applicant.bankAccountStanding[i2-3]": "'good'" + "applicant.employmentMonths[i2-1]": "> 24" + "applicant.incomeVerification[i2-2]": "'complete'" diff --git a/core/engine/tests/snapshots/engine__auto-insurance-premium-calculator_0.snap b/core/engine/tests/snapshots/engine__auto-insurance-premium-calculator_0.snap new file mode 100644 index 00000000..24a7b4f3 --- /dev/null +++ b/core/engine/tests/snapshots/engine__auto-insurance-premium-calculator_0.snap @@ -0,0 +1,355 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + basePremium: + "$serde_json::private::Number": "1650" + basePremiumPerThousand: + "$serde_json::private::Number": "5.5" + coverageAmountInThousands: + "$serde_json::private::Number": "300" + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + riskFactors: + ageRiskFactor: + "$serde_json::private::Number": "1.2" + driverRiskCategory: medium + vehicleRiskFactor: + "$serde_json::private::Number": "1" +trace: + dt1: + id: dt1 + input: + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + name: driverRiskAssessment + order: + "$serde_json::private::Number": "1" + output: + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + riskFactors: + ageRiskFactor: + "$serde_json::private::Number": "1.2" + driverRiskCategory: medium + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + customer.age: + "$serde_json::private::Number": "35" + customer.drivingHistory.accidentsLast3Years + customer.drivingHistory.violationsLast3Years: + "$serde_json::private::Number": "1" + rule: + _id: r1-4 + "customer.age[i1-1]": "[25..65]" + "customer.drivingHistory.accidentsLast3Years + customer.drivingHistory.violationsLast3Years[i1-2]": "1, 2" + dt2: + id: dt2 + input: + basePremium: + "$serde_json::private::Number": "1650" + basePremiumPerThousand: + "$serde_json::private::Number": "5.5" + coverageAmountInThousands: + "$serde_json::private::Number": "300" + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + riskFactors: + ageRiskFactor: + "$serde_json::private::Number": "1.2" + driverRiskCategory: medium + name: vehicleRiskAssessment + order: + "$serde_json::private::Number": "3" + output: + basePremium: + "$serde_json::private::Number": "1650" + basePremiumPerThousand: + "$serde_json::private::Number": "5.5" + coverageAmountInThousands: + "$serde_json::private::Number": "300" + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + riskFactors: + ageRiskFactor: + "$serde_json::private::Number": "1.2" + driverRiskCategory: medium + vehicleRiskFactor: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + policy.vehicleAge: + "$serde_json::private::Number": "3" + policy.vehicleType: sedan + rule: + _id: r2-2 + "policy.vehicleAge[i2-2]": "[3..7]" + "policy.vehicleType[i2-1]": "'sedan'" + dt3: + id: dt3 + input: + basePremium: + "$serde_json::private::Number": "1650" + basePremiumPerThousand: + "$serde_json::private::Number": "5.5" + coverageAmountInThousands: + "$serde_json::private::Number": "300" + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + riskFactors: + ageRiskFactor: + "$serde_json::private::Number": "1.2" + driverRiskCategory: medium + vehicleRiskFactor: + "$serde_json::private::Number": "1" + name: finalPremiumCalculation + order: + "$serde_json::private::Number": "4" + output: + basePremium: + "$serde_json::private::Number": "1650" + basePremiumPerThousand: + "$serde_json::private::Number": "5.5" + coverageAmountInThousands: + "$serde_json::private::Number": "300" + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + riskFactors: + ageRiskFactor: + "$serde_json::private::Number": "1.2" + driverRiskCategory: medium + vehicleRiskFactor: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: ~ + ex1: + id: ex1 + input: + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + riskFactors: + ageRiskFactor: + "$serde_json::private::Number": "1.2" + driverRiskCategory: medium + name: calculateBasePremium + order: + "$serde_json::private::Number": "2" + output: + basePremium: + "$serde_json::private::Number": "1650" + basePremiumPerThousand: + "$serde_json::private::Number": "5.5" + coverageAmountInThousands: + "$serde_json::private::Number": "300" + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + riskFactors: + ageRiskFactor: + "$serde_json::private::Number": "1.2" + driverRiskCategory: medium + performance: "[perf]" + traceData: + basePremium: + result: "1650" + basePremiumPerThousand: + result: "5.5" + coverageAmountInThousands: + result: "300" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + age: + "$serde_json::private::Number": "35" + creditScore: + "$serde_json::private::Number": "720" + drivingHistory: + accidentsLast3Years: + "$serde_json::private::Number": "0" + violationsLast3Years: + "$serde_json::private::Number": "1" + gender: female + policy: + coverageAmount: + "$serde_json::private::Number": "300000" + coverageType: comprehensive + deductible: + "$serde_json::private::Number": "500" + vehicleAge: + "$serde_json::private::Number": "3" + vehicleType: sedan + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__booking-fraud-detection_0.snap b/core/engine/tests/snapshots/engine__booking-fraud-detection_0.snap new file mode 100644 index 00000000..86d6373d --- /dev/null +++ b/core/engine/tests/snapshots/engine__booking-fraud-detection_0.snap @@ -0,0 +1,329 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + flags: + manual_review: true + requires_verification: true +trace: + 9213dd68-a9f4-4b90-ada9-c7418d8b3c51: + id: 9213dd68-a9f4-4b90-ada9-c7418d8b3c51 + input: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + risk: + account: + reason: Normal account history + score: + "$serde_json::private::Number": "0" + pattern: + reason: Multiple rapid bookings + score: + "$serde_json::private::Number": "30" + payment: + reason: High-value prepaid card transaction + score: + "$serde_json::private::Number": "40" + risk_factors: + - Multiple rapid bookings + - High-value prepaid card transaction + total_risk_score: + "$serde_json::private::Number": "70" + name: risk_level + order: + "$serde_json::private::Number": "5" + output: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + risk: + account: + reason: Normal account history + score: + "$serde_json::private::Number": "0" + pattern: + reason: Multiple rapid bookings + score: + "$serde_json::private::Number": "30" + payment: + reason: High-value prepaid card transaction + score: + "$serde_json::private::Number": "40" + risk_factors: + - Multiple rapid bookings + - High-value prepaid card transaction + risk_level: high + total_risk_score: + "$serde_json::private::Number": "70" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + total_risk_score: + "$serde_json::private::Number": "70" + rule: + _id: 42dc5a6d-6605-40b6-83b4-bad0bcf445c6 + "total_risk_score[7385e66d-dc97-4048-a214-3f35d0029465]": ">= 70" + dt1: + id: dt1 + input: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + name: payment_risk + order: + "$serde_json::private::Number": "1" + output: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + risk: + payment: + reason: High-value prepaid card transaction + score: + "$serde_json::private::Number": "40" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + booking.amount: + "$serde_json::private::Number": "2500" + booking.payment_method: prepaid_card + rule: + _id: r1-1 + "booking.amount[i1-2]": "> 2000" + "booking.payment_method[i1-1]": "'prepaid_card'" + dt2: + id: dt2 + input: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + name: pattern_risk + order: + "$serde_json::private::Number": "2" + output: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + risk: + pattern: + reason: Multiple rapid bookings + score: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + account.bookings_last_24h: + "$serde_json::private::Number": "6" + account.country: US + rule: + _id: r2-2 + "account.bookings_last_24h[i2-1]": "> 5" + "account.country[i2-2]": "" + dt3: + id: dt3 + input: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + name: account_risk + order: + "$serde_json::private::Number": "3" + output: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + risk: + account: + reason: Normal account history + score: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + account.age_days: ~ + rule: + _id: r3-4 + "account.age_days[i3-1]": "" + e6dd7428-9ce6-4d8d-9a62-e38af18da14b: + id: e6dd7428-9ce6-4d8d-9a62-e38af18da14b + input: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + risk: + account: + reason: Normal account history + score: + "$serde_json::private::Number": "0" + pattern: + reason: Multiple rapid bookings + score: + "$serde_json::private::Number": "30" + payment: + reason: High-value prepaid card transaction + score: + "$serde_json::private::Number": "40" + risk_factors: + - Multiple rapid bookings + - High-value prepaid card transaction + risk_level: high + total_risk_score: + "$serde_json::private::Number": "70" + name: flags + order: + "$serde_json::private::Number": "6" + output: + flags: + manual_review: true + requires_verification: true + performance: "[perf]" + traceData: + flags.manual_review: + result: "true" + flags.requires_verification: + result: "true" + ex1: + id: ex1 + input: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + risk: + account: + reason: Normal account history + score: + "$serde_json::private::Number": "0" + pattern: + reason: Multiple rapid bookings + score: + "$serde_json::private::Number": "30" + payment: + reason: High-value prepaid card transaction + score: + "$serde_json::private::Number": "40" + name: risk_calculation + order: + "$serde_json::private::Number": "4" + output: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + risk: + account: + reason: Normal account history + score: + "$serde_json::private::Number": "0" + pattern: + reason: Multiple rapid bookings + score: + "$serde_json::private::Number": "30" + payment: + reason: High-value prepaid card transaction + score: + "$serde_json::private::Number": "40" + risk_factors: + - Multiple rapid bookings + - High-value prepaid card transaction + total_risk_score: + "$serde_json::private::Number": "70" + performance: "[perf]" + traceData: + risk_factors: + result: "[\"Multiple rapid bookings\",\"High-value prepaid card transaction\"]" + total_risk_score: + result: "70" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + account: + bookings_last_24h: + "$serde_json::private::Number": "6" + country: US + booking: + amount: + "$serde_json::private::Number": "2500" + ip_country: US + payment_method: prepaid_card + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__booking-personalization-system_0.snap b/core/engine/tests/snapshots/engine__booking-personalization-system_0.snap new file mode 100644 index 00000000..7e40bec9 --- /dev/null +++ b/core/engine/tests/snapshots/engine__booking-personalization-system_0.snap @@ -0,0 +1,482 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + allFeatures: + - standardSearch + - standardNavigation + - joinLoyaltyBanner + - standardOptions + bookingFlowTemplate: basic + totalDiscountPercentage: + "$serde_json::private::Number": "0" +trace: + bookingHistoryTable: + id: bookingHistoryTable + input: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + additionalDiscountPercentage: + "$serde_json::private::Number": "0" + baseDiscountPercentage: + "$serde_json::private::Number": "0" + customerPriority: + "$serde_json::private::Number": "4" + layoutConfig: + imageSize: medium + showExtras: true + type: standard + loyaltyFeatures: + - joinLoyaltyBanner + - standardOptions + showSpecialOffers: false + specialOffersType: standardOffers + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + name: Booking History Personalization + order: + "$serde_json::private::Number": "4" + output: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + additionalDiscountPercentage: + "$serde_json::private::Number": "0" + baseDiscountPercentage: + "$serde_json::private::Number": "0" + customerPriority: + "$serde_json::private::Number": "4" + historyDiscountPercentage: + "$serde_json::private::Number": "0" + layoutConfig: + imageSize: medium + showExtras: true + type: standard + loyaltyFeatures: + - joinLoyaltyBanner + - standardOptions + recommendationType: standard + showRecentlyViewed: false + showSpecialOffers: false + specialOffersType: standardOffers + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + customer.bookingHistory.recentBookings: ~ + customer.bookingHistory.totalBookings: ~ + rule: + _id: bh-rule5 + "customer.bookingHistory.recentBookings[recentBookings]": "" + "customer.bookingHistory.totalBookings[totalBookings]": "" + deviceTypeTable: + id: deviceTypeTable + input: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + name: Device Type Personalization + order: + "$serde_json::private::Number": "1" + output: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + layoutConfig: + imageSize: medium + showExtras: true + type: standard + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + customer.deviceType: ~ + rule: + _id: dt-rule4 + "customer.deviceType[deviceType]": "" + finalPersonalization: + id: finalPersonalization + input: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + additionalDiscountPercentage: + "$serde_json::private::Number": "0" + baseDiscountPercentage: + "$serde_json::private::Number": "0" + customerPriority: + "$serde_json::private::Number": "4" + historyDiscountPercentage: + "$serde_json::private::Number": "0" + layoutConfig: + imageSize: medium + showExtras: true + type: standard + loyaltyFeatures: + - joinLoyaltyBanner + - standardOptions + personalizationScore: + "$serde_json::private::Number": "5" + recommendationType: standard + showRecentlyViewed: false + showSpecialOffers: false + specialOffersType: standardOffers + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + name: Calculate Final Personalization + order: + "$serde_json::private::Number": "6" + output: + allFeatures: + - standardSearch + - standardNavigation + - joinLoyaltyBanner + - standardOptions + bookingFlowTemplate: basic + totalDiscountPercentage: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + allFeatures: + result: "[\"standardSearch\",\"standardNavigation\",\"joinLoyaltyBanner\",\"standardOptions\"]" + bookingFlowTemplate: + result: "\"basic\"" + totalDiscountPercentage: + result: "0" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + performance: "[perf]" + traceData: ~ + loyaltyStatusTable: + id: loyaltyStatusTable + input: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + layoutConfig: + imageSize: medium + showExtras: true + type: standard + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + name: Loyalty Status Personalization + order: + "$serde_json::private::Number": "2" + output: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + baseDiscountPercentage: + "$serde_json::private::Number": "0" + customerPriority: + "$serde_json::private::Number": "4" + layoutConfig: + imageSize: medium + showExtras: true + type: standard + loyaltyFeatures: + - joinLoyaltyBanner + - standardOptions + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + customer.loyaltyStatus: ~ + rule: + _id: ls-rule5 + "customer.loyaltyStatus[loyaltyStatus]": "" + personalizationScoreTable: + id: personalizationScoreTable + input: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + additionalDiscountPercentage: + "$serde_json::private::Number": "0" + baseDiscountPercentage: + "$serde_json::private::Number": "0" + customerPriority: + "$serde_json::private::Number": "4" + historyDiscountPercentage: + "$serde_json::private::Number": "0" + layoutConfig: + imageSize: medium + showExtras: true + type: standard + loyaltyFeatures: + - joinLoyaltyBanner + - standardOptions + recommendationType: standard + showRecentlyViewed: false + showSpecialOffers: false + specialOffersType: standardOffers + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + name: Calculate Personalization Score + order: + "$serde_json::private::Number": "5" + output: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + additionalDiscountPercentage: + "$serde_json::private::Number": "0" + baseDiscountPercentage: + "$serde_json::private::Number": "0" + customerPriority: + "$serde_json::private::Number": "4" + historyDiscountPercentage: + "$serde_json::private::Number": "0" + layoutConfig: + imageSize: medium + showExtras: true + type: standard + loyaltyFeatures: + - joinLoyaltyBanner + - standardOptions + personalizationScore: + "$serde_json::private::Number": "5" + recommendationType: standard + showRecentlyViewed: false + showSpecialOffers: false + specialOffersType: standardOffers + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "12" + reference_map: + customer.bookingHistory.totalBookings: ~ + customer.visitSource: ~ + personalization.customerPriority: + "$serde_json::private::Number": "4" + rule: + _id: ps-rule13 + "customer.bookingHistory.totalBookings[totalBookingsCheck]": "" + "customer.visitSource[visitSourceCheck]": "" + "personalization.customerPriority[loyaltyPriority]": "" + visitSourceTable: + id: visitSourceTable + input: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + baseDiscountPercentage: + "$serde_json::private::Number": "0" + customerPriority: + "$serde_json::private::Number": "4" + layoutConfig: + imageSize: medium + showExtras: true + type: standard + loyaltyFeatures: + - joinLoyaltyBanner + - standardOptions + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + name: Visit Source Personalization + order: + "$serde_json::private::Number": "3" + output: + availableSeats: + "$serde_json::private::Number": "35" + avgCompetitorPrice: + "$serde_json::private::Number": "275" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "5" + demandForecast: + "$serde_json::private::Number": "75" + flightId: FL-123 + personalization: + additionalDiscountPercentage: + "$serde_json::private::Number": "0" + baseDiscountPercentage: + "$serde_json::private::Number": "0" + customerPriority: + "$serde_json::private::Number": "4" + layoutConfig: + imageSize: medium + showExtras: true + type: standard + loyaltyFeatures: + - joinLoyaltyBanner + - standardOptions + showSpecialOffers: false + specialOffersType: standardOffers + uiElements: + - standardSearch + - standardNavigation + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "5" + reference_map: + customer.visitSource: ~ + rule: + _id: vs-rule6 + "customer.visitSource[visitSource]": "" diff --git a/core/engine/tests/snapshots/engine__care-team-assignment-system_0.snap b/core/engine/tests/snapshots/engine__care-team-assignment-system_0.snap new file mode 100644 index 00000000..2867900e --- /dev/null +++ b/core/engine/tests/snapshots/engine__care-team-assignment-system_0.snap @@ -0,0 +1,783 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + ageCategory: senior + careTeam: + complexityLevel: high + coordinator: + priority: high + role: care_coordinator + providers: + - priority: high + role: primary_physician + - priority: medium + role: geriatric_specialist + - priority: medium + role: mental_health_provider + - priority: medium + role: nutritionist + - priority: high + role: nurse_practitioner + - priority: medium + role: physical_therapist + teamSize: "3" + mobilityIssues: true + requiresMentalHealthSupport: true + requiresNutritionSupport: true + requiresSpecialist: true +trace: + dt1: + id: dt1 + input: + availableProviders: + - id: DR001 + languages: + - english + - spanish + name: Dr. Sarah Johnson + role: primary_physician + specialties: + - internal_medicine + - geriatrics + - id: DR002 + languages: + - english + - mandarin + name: Dr. Michael Chen + role: cardiologist + specialties: + - cardiology + - id: DR003 + languages: + - english + name: Dr. Lisa Peterson + role: diabetes_specialist + specialties: + - endocrinology + - id: NP001 + languages: + - english + name: Nancy Williams + role: nurse_practitioner + specialties: + - primary_care + - id: RN001 + languages: + - english + - spanish + name: Robert Garcia + role: nurse + specialties: + - geriatric_care + - id: MH001 + languages: + - english + name: Dr. Emily Cohen + role: mental_health_provider + specialties: + - psychiatry + - geriatric_psychiatry + - id: PT001 + languages: + - english + name: James Wilson + role: physical_therapist + specialties: + - geriatric_physical_therapy + - id: CC001 + languages: + - english + - spanish + name: Maria Rodriguez + role: care_coordinator + specialties: + - complex_care_coordination + facility: + department: Internal Medicine + id: FAC789 + name: Memorial Medical Center + patient: + age: + "$serde_json::private::Number": "67" + careComplexity: high + carePreferences: + preferredGender: any + preferredLanguage: english + requiresTranslator: false + conditions: + - diabetes + - heart_disease + - hypertension + - depression + gender: male + id: PT12345 + insuranceType: medicare + mobilityScore: + "$serde_json::private::Number": "35" + name: John Smith + primaryLanguage: english + name: determine_complexity + order: + "$serde_json::private::Number": "1" + output: + availableProviders: + - id: DR001 + languages: + - english + - spanish + name: Dr. Sarah Johnson + role: primary_physician + specialties: + - internal_medicine + - geriatrics + - id: DR002 + languages: + - english + - mandarin + name: Dr. Michael Chen + role: cardiologist + specialties: + - cardiology + - id: DR003 + languages: + - english + name: Dr. Lisa Peterson + role: diabetes_specialist + specialties: + - endocrinology + - id: NP001 + languages: + - english + name: Nancy Williams + role: nurse_practitioner + specialties: + - primary_care + - id: RN001 + languages: + - english + - spanish + name: Robert Garcia + role: nurse + specialties: + - geriatric_care + - id: MH001 + languages: + - english + name: Dr. Emily Cohen + role: mental_health_provider + specialties: + - psychiatry + - geriatric_psychiatry + - id: PT001 + languages: + - english + name: James Wilson + role: physical_therapist + specialties: + - geriatric_physical_therapy + - id: CC001 + languages: + - english + - spanish + name: Maria Rodriguez + role: care_coordinator + specialties: + - complex_care_coordination + careTeam: + complexityLevel: high + teamSize: "3" + facility: + department: Internal Medicine + id: FAC789 + name: Memorial Medical Center + patient: + age: + "$serde_json::private::Number": "67" + careComplexity: high + carePreferences: + preferredGender: any + preferredLanguage: english + requiresTranslator: false + conditions: + - diabetes + - heart_disease + - hypertension + - depression + gender: male + id: PT12345 + insuranceType: medicare + mobilityScore: + "$serde_json::private::Number": "35" + name: John Smith + primaryLanguage: english + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + patient.careComplexity: high + rule: + _id: r1-1 + "patient.careComplexity[i1-1]": "\"high\"" + dt2: + id: dt2 + input: + ageCategory: senior + careTeam: + complexityLevel: high + teamSize: "3" + mobilityIssues: true + requiresMentalHealthSupport: true + requiresNutritionSupport: true + requiresSpecialist: true + name: assign_providers + order: + "$serde_json::private::Number": "4" + output: + ageCategory: senior + careTeam: + complexityLevel: high + providers: + - priority: high + role: primary_physician + - priority: medium + role: geriatric_specialist + - priority: medium + role: mental_health_provider + - priority: medium + role: nutritionist + - priority: high + role: nurse_practitioner + - priority: medium + role: physical_therapist + teamSize: "3" + mobilityIssues: true + requiresMentalHealthSupport: true + requiresNutritionSupport: true + requiresSpecialist: true + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: + careTeam.complexityLevel: high + rule: + _id: r2-1 + "careTeam.complexityLevel[i2-1]": "\"high\"" + - index: + "$serde_json::private::Number": "2" + reference_map: + careTeam.complexityLevel: high + rule: + _id: r2-3 + "careTeam.complexityLevel[i2-1]": "" + - index: + "$serde_json::private::Number": "7" + reference_map: + careTeam.complexityLevel: high + rule: + _id: r2-8 + "careTeam.complexityLevel[i2-1]": "" + - index: + "$serde_json::private::Number": "8" + reference_map: + careTeam.complexityLevel: high + rule: + _id: r2-9 + "careTeam.complexityLevel[i2-1]": "" + - index: + "$serde_json::private::Number": "9" + reference_map: + careTeam.complexityLevel: high + rule: + _id: r2-10 + "careTeam.complexityLevel[i2-1]": "\"high\"" + - index: + "$serde_json::private::Number": "11" + reference_map: + careTeam.complexityLevel: high + rule: + _id: r2-12 + "careTeam.complexityLevel[i2-1]": "" + dt3: + id: dt3 + input: + ageCategory: senior + careTeam: + complexityLevel: high + providers: + - priority: high + role: primary_physician + - priority: medium + role: geriatric_specialist + - priority: medium + role: mental_health_provider + - priority: medium + role: nutritionist + - priority: high + role: nurse_practitioner + - priority: medium + role: physical_therapist + teamSize: "3" + mobilityIssues: true + requiresMentalHealthSupport: true + requiresNutritionSupport: true + requiresSpecialist: true + name: assign_coordinator + order: + "$serde_json::private::Number": "5" + output: + ageCategory: senior + careTeam: + complexityLevel: high + coordinator: + priority: high + role: care_coordinator + providers: + - priority: high + role: primary_physician + - priority: medium + role: geriatric_specialist + - priority: medium + role: mental_health_provider + - priority: medium + role: nutritionist + - priority: high + role: nurse_practitioner + - priority: medium + role: physical_therapist + teamSize: "3" + mobilityIssues: true + requiresMentalHealthSupport: true + requiresNutritionSupport: true + requiresSpecialist: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + $: high + careTeam.complexityLevel: high + rule: + "$[i3-2]": len(careTeam.providers) > 5 + _id: r3-1 + "careTeam.complexityLevel[i3-1]": "\"high\"" + ex1: + id: ex1 + input: + ageCategory: senior + availableProviders: + - id: DR001 + languages: + - english + - spanish + name: Dr. Sarah Johnson + role: primary_physician + specialties: + - internal_medicine + - geriatrics + - id: DR002 + languages: + - english + - mandarin + name: Dr. Michael Chen + role: cardiologist + specialties: + - cardiology + - id: DR003 + languages: + - english + name: Dr. Lisa Peterson + role: diabetes_specialist + specialties: + - endocrinology + - id: NP001 + languages: + - english + name: Nancy Williams + role: nurse_practitioner + specialties: + - primary_care + - id: RN001 + languages: + - english + - spanish + name: Robert Garcia + role: nurse + specialties: + - geriatric_care + - id: MH001 + languages: + - english + name: Dr. Emily Cohen + role: mental_health_provider + specialties: + - psychiatry + - geriatric_psychiatry + - id: PT001 + languages: + - english + name: James Wilson + role: physical_therapist + specialties: + - geriatric_physical_therapy + - id: CC001 + languages: + - english + - spanish + name: Maria Rodriguez + role: care_coordinator + specialties: + - complex_care_coordination + careTeam: + complexityLevel: high + teamSize: "3" + facility: + department: Internal Medicine + id: FAC789 + name: Memorial Medical Center + patient: + age: + "$serde_json::private::Number": "67" + careComplexity: high + carePreferences: + preferredGender: any + preferredLanguage: english + requiresTranslator: false + conditions: + - diabetes + - heart_disease + - hypertension + - depression + gender: male + id: PT12345 + insuranceType: medicare + mobilityScore: + "$serde_json::private::Number": "35" + name: John Smith + primaryLanguage: english + name: evaluate_patient_needs + order: + "$serde_json::private::Number": "3" + output: + ageCategory: senior + careTeam: + complexityLevel: high + teamSize: "3" + mobilityIssues: true + requiresMentalHealthSupport: true + requiresNutritionSupport: true + requiresSpecialist: true + performance: "[perf]" + traceData: + availableProviders: + result: "null" + facility: + result: "null" + mobilityIssues: + result: "true" + patient: + result: "null" + requiresMentalHealthSupport: + result: "true" + requiresNutritionSupport: + result: "true" + requiresSpecialist: + result: "true" + f1af25e2-126e-4882-8d35-6ae33dbc37bf: + id: f1af25e2-126e-4882-8d35-6ae33dbc37bf + input: + availableProviders: + - id: DR001 + languages: + - english + - spanish + name: Dr. Sarah Johnson + role: primary_physician + specialties: + - internal_medicine + - geriatrics + - id: DR002 + languages: + - english + - mandarin + name: Dr. Michael Chen + role: cardiologist + specialties: + - cardiology + - id: DR003 + languages: + - english + name: Dr. Lisa Peterson + role: diabetes_specialist + specialties: + - endocrinology + - id: NP001 + languages: + - english + name: Nancy Williams + role: nurse_practitioner + specialties: + - primary_care + - id: RN001 + languages: + - english + - spanish + name: Robert Garcia + role: nurse + specialties: + - geriatric_care + - id: MH001 + languages: + - english + name: Dr. Emily Cohen + role: mental_health_provider + specialties: + - psychiatry + - geriatric_psychiatry + - id: PT001 + languages: + - english + name: James Wilson + role: physical_therapist + specialties: + - geriatric_physical_therapy + - id: CC001 + languages: + - english + - spanish + name: Maria Rodriguez + role: care_coordinator + specialties: + - complex_care_coordination + careTeam: + complexityLevel: high + teamSize: "3" + facility: + department: Internal Medicine + id: FAC789 + name: Memorial Medical Center + patient: + age: + "$serde_json::private::Number": "67" + careComplexity: high + carePreferences: + preferredGender: any + preferredLanguage: english + requiresTranslator: false + conditions: + - diabetes + - heart_disease + - hypertension + - depression + gender: male + id: PT12345 + insuranceType: medicare + mobilityScore: + "$serde_json::private::Number": "35" + name: John Smith + primaryLanguage: english + name: age_category + order: + "$serde_json::private::Number": "2" + output: + ageCategory: senior + availableProviders: + - id: DR001 + languages: + - english + - spanish + name: Dr. Sarah Johnson + role: primary_physician + specialties: + - internal_medicine + - geriatrics + - id: DR002 + languages: + - english + - mandarin + name: Dr. Michael Chen + role: cardiologist + specialties: + - cardiology + - id: DR003 + languages: + - english + name: Dr. Lisa Peterson + role: diabetes_specialist + specialties: + - endocrinology + - id: NP001 + languages: + - english + name: Nancy Williams + role: nurse_practitioner + specialties: + - primary_care + - id: RN001 + languages: + - english + - spanish + name: Robert Garcia + role: nurse + specialties: + - geriatric_care + - id: MH001 + languages: + - english + name: Dr. Emily Cohen + role: mental_health_provider + specialties: + - psychiatry + - geriatric_psychiatry + - id: PT001 + languages: + - english + name: James Wilson + role: physical_therapist + specialties: + - geriatric_physical_therapy + - id: CC001 + languages: + - english + - spanish + name: Maria Rodriguez + role: care_coordinator + specialties: + - complex_care_coordination + careTeam: + complexityLevel: high + teamSize: "3" + facility: + department: Internal Medicine + id: FAC789 + name: Memorial Medical Center + patient: + age: + "$serde_json::private::Number": "67" + careComplexity: high + carePreferences: + preferredGender: any + preferredLanguage: english + requiresTranslator: false + conditions: + - diabetes + - heart_disease + - hypertension + - depression + gender: male + id: PT12345 + insuranceType: medicare + mobilityScore: + "$serde_json::private::Number": "35" + name: John Smith + primaryLanguage: english + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + patient.age: + "$serde_json::private::Number": "67" + rule: + _id: r1-3 + "patient.age[i1-1]": "" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + availableProviders: + - id: DR001 + languages: + - english + - spanish + name: Dr. Sarah Johnson + role: primary_physician + specialties: + - internal_medicine + - geriatrics + - id: DR002 + languages: + - english + - mandarin + name: Dr. Michael Chen + role: cardiologist + specialties: + - cardiology + - id: DR003 + languages: + - english + name: Dr. Lisa Peterson + role: diabetes_specialist + specialties: + - endocrinology + - id: NP001 + languages: + - english + name: Nancy Williams + role: nurse_practitioner + specialties: + - primary_care + - id: RN001 + languages: + - english + - spanish + name: Robert Garcia + role: nurse + specialties: + - geriatric_care + - id: MH001 + languages: + - english + name: Dr. Emily Cohen + role: mental_health_provider + specialties: + - psychiatry + - geriatric_psychiatry + - id: PT001 + languages: + - english + name: James Wilson + role: physical_therapist + specialties: + - geriatric_physical_therapy + - id: CC001 + languages: + - english + - spanish + name: Maria Rodriguez + role: care_coordinator + specialties: + - complex_care_coordination + facility: + department: Internal Medicine + id: FAC789 + name: Memorial Medical Center + patient: + age: + "$serde_json::private::Number": "67" + careComplexity: high + carePreferences: + preferredGender: any + preferredLanguage: english + requiresTranslator: false + conditions: + - diabetes + - heart_disease + - hypertension + - depression + gender: male + id: PT12345 + insuranceType: medicare + mobilityScore: + "$serde_json::private::Number": "35" + name: John Smith + primaryLanguage: english + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__cellular-data-rollover-system_0.snap b/core/engine/tests/snapshots/engine__cellular-data-rollover-system_0.snap new file mode 100644 index 00000000..8fd179cf --- /dev/null +++ b/core/engine/tests/snapshots/engine__cellular-data-rollover-system_0.snap @@ -0,0 +1,230 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + nextBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "2" + status: approved + responseMessage: Rollover successful. You have 20 GB of rollover data available for your next billing cycle. +trace: + dt1: + id: dt1 + input: + currentBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "1" + dataUsed: + "$serde_json::private::Number": "35" + rolloverData: + "$serde_json::private::Number": "5" + isPositiveUnusedData: true + plan: + monthlyDataAllowance: + "$serde_json::private::Number": "50" + rolloverEligible: true + type: premium + previousRolloverAmount: + "$serde_json::private::Number": "5" + unusedData: + "$serde_json::private::Number": "15" + name: determineRolloverAmount + order: + "$serde_json::private::Number": "2" + output: + currentBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "1" + dataUsed: + "$serde_json::private::Number": "35" + rolloverData: + "$serde_json::private::Number": "5" + isPositiveUnusedData: true + nextBillingCycle: + rolloverData: + "$serde_json::private::Number": "20" + rolloverReason: Unlimited rollover for Premium plan + plan: + monthlyDataAllowance: + "$serde_json::private::Number": "50" + rolloverEligible: true + type: premium + previousRolloverAmount: + "$serde_json::private::Number": "5" + unusedData: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + currentBillingCycle.consecutiveRollovers: + "$serde_json::private::Number": "1" + isPositiveUnusedData: true + plan.type: premium + rule: + _id: r1-1 + "currentBillingCycle.consecutiveRollovers[i1-3]": "< 3" + "isPositiveUnusedData[i1-2]": "true" + "plan.type[i1-1]": "'premium'" + ex1: + id: ex1 + input: + currentBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "1" + dataUsed: + "$serde_json::private::Number": "35" + rolloverData: + "$serde_json::private::Number": "5" + plan: + monthlyDataAllowance: + "$serde_json::private::Number": "50" + rolloverEligible: true + type: premium + name: calculateUnusedData + order: + "$serde_json::private::Number": "1" + output: + currentBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "1" + dataUsed: + "$serde_json::private::Number": "35" + rolloverData: + "$serde_json::private::Number": "5" + isPositiveUnusedData: true + plan: + monthlyDataAllowance: + "$serde_json::private::Number": "50" + rolloverEligible: true + type: premium + previousRolloverAmount: + "$serde_json::private::Number": "5" + unusedData: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: + isPositiveUnusedData: + result: "true" + previousRolloverAmount: + result: "5" + unusedData: + result: "15" + ex2: + id: ex2 + input: + currentBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "1" + dataUsed: + "$serde_json::private::Number": "35" + rolloverData: + "$serde_json::private::Number": "5" + isPositiveUnusedData: true + nextBillingCycle: + rolloverData: + "$serde_json::private::Number": "20" + rolloverReason: Unlimited rollover for Premium plan + plan: + monthlyDataAllowance: + "$serde_json::private::Number": "50" + rolloverEligible: true + type: premium + previousRolloverAmount: + "$serde_json::private::Number": "5" + unusedData: + "$serde_json::private::Number": "15" + name: processSuccessfulRollover + order: + "$serde_json::private::Number": "4" + output: + nextBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "2" + status: approved + responseMessage: Rollover successful. You have 20 GB of rollover data available for your next billing cycle. + performance: "[perf]" + traceData: + nextBillingCycle.consecutiveRollovers: + result: "2" + nextBillingCycle.status: + result: "\"approved\"" + responseMessage: + result: "\"Rollover successful. You have 20 GB of rollover data available for your next billing cycle.\"" + ip1: + id: ip1 + input: ~ + name: dataRolloverRequest + order: + "$serde_json::private::Number": "0" + output: + currentBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "1" + dataUsed: + "$serde_json::private::Number": "35" + rolloverData: + "$serde_json::private::Number": "5" + plan: + monthlyDataAllowance: + "$serde_json::private::Number": "50" + rolloverEligible: true + type: premium + performance: "[perf]" + traceData: ~ + sw1: + id: sw1 + input: + currentBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "1" + dataUsed: + "$serde_json::private::Number": "35" + rolloverData: + "$serde_json::private::Number": "5" + isPositiveUnusedData: true + nextBillingCycle: + rolloverData: + "$serde_json::private::Number": "20" + rolloverReason: Unlimited rollover for Premium plan + plan: + monthlyDataAllowance: + "$serde_json::private::Number": "50" + rolloverEligible: true + type: premium + previousRolloverAmount: + "$serde_json::private::Number": "5" + unusedData: + "$serde_json::private::Number": "15" + name: verifyRollover + order: + "$serde_json::private::Number": "3" + output: + currentBillingCycle: + consecutiveRollovers: + "$serde_json::private::Number": "1" + dataUsed: + "$serde_json::private::Number": "35" + rolloverData: + "$serde_json::private::Number": "5" + isPositiveUnusedData: true + nextBillingCycle: + rolloverData: + "$serde_json::private::Number": "20" + rolloverReason: Unlimited rollover for Premium plan + plan: + monthlyDataAllowance: + "$serde_json::private::Number": "50" + rolloverEligible: true + type: premium + previousRolloverAmount: + "$serde_json::private::Number": "5" + unusedData: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: + statements: + - id: s1-1 diff --git a/core/engine/tests/snapshots/engine__claim-validation-system_0.snap b/core/engine/tests/snapshots/engine__claim-validation-system_0.snap new file mode 100644 index 00000000..441ce3a1 --- /dev/null +++ b/core/engine/tests/snapshots/engine__claim-validation-system_0.snap @@ -0,0 +1,227 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + isValid: false + nextStep: rejection + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + validation: + claimDetailsReason: "" + claimDetailsValid: true + policyStatusValid: true + timeframesReason: Claim reported more than 60 days after incident + timeframesValid: false + validationMessage: Claim reported more than 60 days after incident +trace: + checkPolicyStatus: + id: checkPolicyStatus + input: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + validation: + claimDetailsReason: "" + claimDetailsValid: true + name: checkPolicyStatus + order: + "$serde_json::private::Number": "2" + output: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + validation: + claimDetailsReason: "" + claimDetailsValid: true + policyStatusValid: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: {} + rule: + _id: r2-5 + determineOutcome: + id: determineOutcome + input: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + validation: + claimDetailsReason: "" + claimDetailsValid: true + policyStatusValid: true + timeframesReason: Claim reported more than 60 days after incident + timeframesValid: false + name: determineOutcome + order: + "$serde_json::private::Number": "4" + output: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + isValid: false + nextStep: rejection + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + validation: + claimDetailsReason: "" + claimDetailsValid: true + policyStatusValid: true + timeframesReason: Claim reported more than 60 days after incident + timeframesValid: false + validationMessage: Claim reported more than 60 days after incident + performance: "[perf]" + traceData: + isValid: + result: "false" + nextStep: + result: "\"rejection\"" + validationMessage: + result: "\"Claim reported more than 60 days after incident\"" + evaluateTimeframes: + id: evaluateTimeframes + input: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + validation: + claimDetailsReason: "" + claimDetailsValid: true + policyStatusValid: true + name: evaluateTimeframes + order: + "$serde_json::private::Number": "3" + output: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + validation: + claimDetailsReason: "" + claimDetailsValid: true + policyStatusValid: true + timeframesReason: Claim reported more than 60 days after incident + timeframesValid: false + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: r3-2 + input: + id: input + input: ~ + name: claimRequest + order: + "$serde_json::private::Number": "0" + output: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + performance: "[perf]" + traceData: ~ + validateClaimDetails: + id: validateClaimDetails + input: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + name: validateClaimDetails + order: + "$serde_json::private::Number": "1" + output: + claimNumber: CLM12345 + claimType: property + damageAmount: + "$serde_json::private::Number": "1500" + description: Water damage from burst pipe in kitchen + incidentDate: + "$serde_json::private::Number": "1640995200" + policyNumber: POL98765432 + policyStartDate: + "$serde_json::private::Number": "1609459200" + policyStatus: active + validation: + claimDetailsReason: "" + claimDetailsValid: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: {} + rule: + _id: r1-5 diff --git a/core/engine/tests/snapshots/engine__clinical-lab-result-interpreter_0.snap b/core/engine/tests/snapshots/engine__clinical-lab-result-interpreter_0.snap new file mode 100644 index 00000000..35e23310 --- /dev/null +++ b/core/engine/tests/snapshots/engine__clinical-lab-result-interpreter_0.snap @@ -0,0 +1,478 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + followUp: + actionRequired: Immediate provider notification required + timeframe: 24 hours + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + riskAssessment: + clinicalRecommendation: Schedule follow-up within 48 hours; consider insulin adjustment + level: high-risk + testResults: + - condition: Hyperglycemia + date: 2025-03-15 + flag: abnormal + recommendation: Monitor closely; adjust diabetes management if applicable + testType: glucose + value: + "$serde_json::private::Number": "260" + - condition: Hypokalemia + date: 2025-03-15 + flag: critical + recommendation: Urgent electrolyte replacement; ECG monitoring required + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - condition: Elevated Creatinine + date: 2025-03-15 + flag: abnormal + recommendation: Evaluate kidney function; adjust medication dosages as needed + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + urgencyLevel: urgent +trace: + dt1: + id: dt1 + input: + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + testResults: + - date: 2025-03-15 + testType: glucose + value: + "$serde_json::private::Number": "260" + - date: 2025-03-15 + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - date: 2025-03-15 + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + name: basicLabEvaluation + order: + "$serde_json::private::Number": "1" + output: + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + testResults: + - condition: Hyperglycemia + date: 2025-03-15 + flag: abnormal + recommendation: Monitor closely; adjust diabetes management if applicable + testType: glucose + value: + "$serde_json::private::Number": "260" + - condition: Hypokalemia + date: 2025-03-15 + flag: critical + recommendation: Urgent electrolyte replacement; ECG monitoring required + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - condition: Elevated Creatinine + date: 2025-03-15 + flag: abnormal + recommendation: Evaluate kidney function; adjust medication dosages as needed + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "4" + reference_map: + testType: glucose + value: + "$serde_json::private::Number": "260" + rule: + _id: r1-5 + "testType[i1-2]": "'glucose'" + "value[i1-1]": "> 200" + - index: + "$serde_json::private::Number": "0" + reference_map: + testType: potassium + value: + "$serde_json::private::Number": "3.2" + rule: + _id: r1-1 + "testType[i1-2]": "'potassium'" + "value[i1-1]": "< 3.5" + - index: + "$serde_json::private::Number": "6" + reference_map: + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + rule: + _id: r1-7 + "testType[i1-2]": "'creatinine'" + "value[i1-1]": "> 1.5" + dt2: + id: dt2 + input: + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + testResults: + - condition: Hyperglycemia + date: 2025-03-15 + flag: abnormal + recommendation: Monitor closely; adjust diabetes management if applicable + testType: glucose + value: + "$serde_json::private::Number": "260" + - condition: Hypokalemia + date: 2025-03-15 + flag: critical + recommendation: Urgent electrolyte replacement; ECG monitoring required + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - condition: Elevated Creatinine + date: 2025-03-15 + flag: abnormal + recommendation: Evaluate kidney function; adjust medication dosages as needed + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + name: patientContextEvaluation + order: + "$serde_json::private::Number": "2" + output: + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + riskAssessment: + clinicalRecommendation: Schedule follow-up within 48 hours; consider insulin adjustment + level: high-risk + testResults: + - condition: Hyperglycemia + date: 2025-03-15 + flag: abnormal + recommendation: Monitor closely; adjust diabetes management if applicable + testType: glucose + value: + "$serde_json::private::Number": "260" + - condition: Hypokalemia + date: 2025-03-15 + flag: critical + recommendation: Urgent electrolyte replacement; ECG monitoring required + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - condition: Elevated Creatinine + date: 2025-03-15 + flag: abnormal + recommendation: Evaluate kidney function; adjust medication dosages as needed + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + patientHistory.conditions: + - diabetes + - hypertension + patientHistory.medications: + - metformin + - lisinopril + - atorvastatin + rule: + _id: r2-1 + "patientHistory.conditions[i2-1]": "'diabetes' in $" + "patientHistory.medications[i2-2]": "some($, # in ['metformin', 'insulin', 'glipizide'])" + dt3: + id: dt3 + input: + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + riskAssessment: + clinicalRecommendation: Schedule follow-up within 48 hours; consider insulin adjustment + level: high-risk + testResults: + - condition: Hyperglycemia + date: 2025-03-15 + flag: abnormal + recommendation: Monitor closely; adjust diabetes management if applicable + testType: glucose + value: + "$serde_json::private::Number": "260" + - condition: Hypokalemia + date: 2025-03-15 + flag: critical + recommendation: Urgent electrolyte replacement; ECG monitoring required + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - condition: Elevated Creatinine + date: 2025-03-15 + flag: abnormal + recommendation: Evaluate kidney function; adjust medication dosages as needed + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + urgencyLevel: urgent + name: followUpDetermination + order: + "$serde_json::private::Number": "4" + output: + followUp: + actionRequired: Immediate provider notification required + timeframe: 24 hours + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + riskAssessment: + clinicalRecommendation: Schedule follow-up within 48 hours; consider insulin adjustment + level: high-risk + testResults: + - condition: Hyperglycemia + date: 2025-03-15 + flag: abnormal + recommendation: Monitor closely; adjust diabetes management if applicable + testType: glucose + value: + "$serde_json::private::Number": "260" + - condition: Hypokalemia + date: 2025-03-15 + flag: critical + recommendation: Urgent electrolyte replacement; ECG monitoring required + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - condition: Elevated Creatinine + date: 2025-03-15 + flag: abnormal + recommendation: Evaluate kidney function; adjust medication dosages as needed + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + urgencyLevel: urgent + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + urgencyLevel: urgent + rule: + _id: r3-1 + "urgencyLevel[i3-1]": "'urgent'" + dt4: + id: dt4 + input: + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + riskAssessment: + clinicalRecommendation: Schedule follow-up within 48 hours; consider insulin adjustment + level: high-risk + testResults: + - condition: Hyperglycemia + date: 2025-03-15 + flag: abnormal + recommendation: Monitor closely; adjust diabetes management if applicable + testType: glucose + value: + "$serde_json::private::Number": "260" + - condition: Hypokalemia + date: 2025-03-15 + flag: critical + recommendation: Urgent electrolyte replacement; ECG monitoring required + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - condition: Elevated Creatinine + date: 2025-03-15 + flag: abnormal + recommendation: Evaluate kidney function; adjust medication dosages as needed + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + name: urgencyAssessment + order: + "$serde_json::private::Number": "3" + output: + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + riskAssessment: + clinicalRecommendation: Schedule follow-up within 48 hours; consider insulin adjustment + level: high-risk + testResults: + - condition: Hyperglycemia + date: 2025-03-15 + flag: abnormal + recommendation: Monitor closely; adjust diabetes management if applicable + testType: glucose + value: + "$serde_json::private::Number": "260" + - condition: Hypokalemia + date: 2025-03-15 + flag: critical + recommendation: Urgent electrolyte replacement; ECG monitoring required + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - condition: Elevated Creatinine + date: 2025-03-15 + flag: abnormal + recommendation: Evaluate kidney function; adjust medication dosages as needed + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + urgencyLevel: urgent + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: r4-1 + ip1: + id: ip1 + input: ~ + name: labResults + order: + "$serde_json::private::Number": "0" + output: + patientHistory: + allergies: + - penicillin + conditions: + - diabetes + - hypertension + medications: + - metformin + - lisinopril + - atorvastatin + testResults: + - date: 2025-03-15 + testType: glucose + value: + "$serde_json::private::Number": "260" + - date: 2025-03-15 + testType: potassium + value: + "$serde_json::private::Number": "3.2" + - date: 2025-03-15 + testType: hemoglobin + value: + "$serde_json::private::Number": "10.2" + - date: 2025-03-15 + testType: creatinine + value: + "$serde_json::private::Number": "1.7" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__clinical-pathway-selection_0.snap b/core/engine/tests/snapshots/engine__clinical-pathway-selection_0.snap new file mode 100644 index 00000000..4aee4a7c --- /dev/null +++ b/core/engine/tests/snapshots/engine__clinical-pathway-selection_0.snap @@ -0,0 +1,638 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + followupFrequency: daily + recommendedMonitoring: + - comprehensive_vitals + - medication_adherence + - lifestyle_factors + - specialist_consultation + selectedPathway: intensive +trace: + comorbidityCheck: + id: comorbidityCheck + input: + evaluation: + baseRiskScore: + "$serde_json::private::Number": "8" + clinicalDomain: cardiac + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + name: comorbidityEvaluation + order: + "$serde_json::private::Number": "2" + output: + comorbidityCount: + "$serde_json::private::Number": "3" + comorbidityRiskScore: + "$serde_json::private::Number": "9" + evaluation: + baseRiskScore: + "$serde_json::private::Number": "8" + clinicalDomain: cardiac + hasHighRiskComorbidity: true + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + totalRiskScore: + "$serde_json::private::Number": "17" + performance: "[perf]" + traceData: + comorbidityCount: + result: "3" + comorbidityRiskScore: + result: "9" + hasHighRiskComorbidity: + result: "true" + totalRiskScore: + result: "17" + diagnoseTable: + id: diagnoseTable + input: + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + name: diagnosisEvaluation + order: + "$serde_json::private::Number": "1" + output: + evaluation: + baseRiskScore: + "$serde_json::private::Number": "8" + clinicalDomain: cardiac + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + patient.primaryDiagnosis: heart_failure + patient.severityScore: + "$serde_json::private::Number": "3" + rule: + _id: r1 + "patient.primaryDiagnosis[i1]": "'heart_failure'" + "patient.severityScore[i2]": "> 2" + finalPathwaySwitch: + id: finalPathwaySwitch + input: + comorbidityCount: + "$serde_json::private::Number": "3" + comorbidityRiskScore: + "$serde_json::private::Number": "9" + evaluation: + additionalRiskScore: + "$serde_json::private::Number": "2" + baseRiskScore: + "$serde_json::private::Number": "8" + clinicalDomain: cardiac + patientRiskCategory: moderate + hasHighRiskComorbidity: true + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + totalRiskScore: + "$serde_json::private::Number": "17" + name: pathwaySelection + order: + "$serde_json::private::Number": "4" + output: + comorbidityCount: + "$serde_json::private::Number": "3" + comorbidityRiskScore: + "$serde_json::private::Number": "9" + evaluation: + additionalRiskScore: + "$serde_json::private::Number": "2" + baseRiskScore: + "$serde_json::private::Number": "8" + clinicalDomain: cardiac + patientRiskCategory: moderate + hasHighRiskComorbidity: true + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + totalRiskScore: + "$serde_json::private::Number": "17" + performance: "[perf]" + traceData: + statements: + - id: intensive + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + performance: "[perf]" + traceData: ~ + intensivePathway: + id: intensivePathway + input: + comorbidityCount: + "$serde_json::private::Number": "3" + comorbidityRiskScore: + "$serde_json::private::Number": "9" + evaluation: + additionalRiskScore: + "$serde_json::private::Number": "2" + baseRiskScore: + "$serde_json::private::Number": "8" + clinicalDomain: cardiac + patientRiskCategory: moderate + hasHighRiskComorbidity: true + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + totalRiskScore: + "$serde_json::private::Number": "17" + name: intensivePathway + order: + "$serde_json::private::Number": "5" + output: + followupFrequency: daily + recommendedMonitoring: + - comprehensive_vitals + - medication_adherence + - lifestyle_factors + - specialist_consultation + selectedPathway: intensive + performance: "[perf]" + traceData: + followupFrequency: + result: "\"daily\"" + recommendedMonitoring: + result: "[\"comprehensive_vitals\",\"medication_adherence\",\"lifestyle_factors\",\"specialist_consultation\"]" + selectedPathway: + result: "\"intensive\"" + patientFactorsTable: + id: patientFactorsTable + input: + comorbidityCount: + "$serde_json::private::Number": "3" + comorbidityRiskScore: + "$serde_json::private::Number": "9" + evaluation: + baseRiskScore: + "$serde_json::private::Number": "8" + clinicalDomain: cardiac + hasHighRiskComorbidity: true + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + totalRiskScore: + "$serde_json::private::Number": "17" + name: patientFactorsEvaluation + order: + "$serde_json::private::Number": "3" + output: + comorbidityCount: + "$serde_json::private::Number": "3" + comorbidityRiskScore: + "$serde_json::private::Number": "9" + evaluation: + additionalRiskScore: + "$serde_json::private::Number": "2" + baseRiskScore: + "$serde_json::private::Number": "8" + clinicalDomain: cardiac + patientRiskCategory: moderate + hasHighRiskComorbidity: true + patient: + age: + "$serde_json::private::Number": "72" + bmi: + "$serde_json::private::Number": "24" + comorbidities: + - diabetes + - hypertension + - kidney_disease + currentMedications: + - dosage: 10mg + frequency: daily + name: Lisinopril + - dosage: 500mg + frequency: twice daily + name: Metformin + - dosage: 40mg + frequency: daily + name: Furosemide + id: P1234567 + labResults: + bnp: + "$serde_json::private::Number": "450" + creatinine: + "$serde_json::private::Number": "1.4" + hba1c: + "$serde_json::private::Number": "7.8" + potassium: + "$serde_json::private::Number": "4.2" + primaryDiagnosis: heart_failure + severityScore: + "$serde_json::private::Number": "3" + vitalSigns: + bloodPressure: + diastolic: + "$serde_json::private::Number": "85" + systolic: + "$serde_json::private::Number": "142" + heartRate: + "$serde_json::private::Number": "88" + oxygenSaturation: + "$serde_json::private::Number": "94" + temperature: + "$serde_json::private::Number": "37.1" + totalRiskScore: + "$serde_json::private::Number": "17" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + patient.age: + "$serde_json::private::Number": "72" + patient.bmi: + "$serde_json::private::Number": "24" + rule: + _id: r2 + "patient.age[i1]": "> 70" + "patient.bmi[i2]": "< 25" diff --git a/core/engine/tests/snapshots/engine__clinical-treatment-protocol_0.snap b/core/engine/tests/snapshots/engine__clinical-treatment-protocol_0.snap new file mode 100644 index 00000000..f001eeb9 --- /dev/null +++ b/core/engine/tests/snapshots/engine__clinical-treatment-protocol_0.snap @@ -0,0 +1,297 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + protocol_name: oral_medication_moderate + treatment_protocol: + base_treatment: oral_medication + dosage_instruction: standard_elderly + follow_up_frequency: bi-weekly + protocol_id: oral_medication_moderate_intensive + protocol_intensity: intensive + risk_adjustment: modified_treatment + severity_level: moderate_diabetes +trace: + diagnoseTable: + id: diagnoseTable + input: + diagnosis: diabetes_type2 + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + name: diagnosisEvaluation + order: + "$serde_json::private::Number": "1" + output: + base_treatment: oral_medication + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + diagnosis: diabetes_type2 + measurement_value: + "$serde_json::private::Number": "8.2" + rule: + _id: rule2 + "diagnosis[i1-1]": "'diabetes_type2'" + "measurement_value[i1-2]": "[7.0..8.5]" + followUpSchedule: + id: followUpSchedule + input: + base_treatment: oral_medication + comorbidity_risk_level: high + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + dosage_modification: standard_elderly + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + patient_risk_category: moderate + protocol_intensity: intensive + risk_adjustment: modified_treatment + name: followUpDetermination + order: + "$serde_json::private::Number": "5" + output: + base_treatment: oral_medication + comorbidity_risk_level: high + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + dosage_modification: standard_elderly + follow_up_schedule: bi-weekly + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + patient_risk_category: moderate + protocol_intensity: intensive + risk_adjustment: modified_treatment + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + comorbidity_risk_level: high + rule: + _id: fs2 + "comorbidity_risk_level[i5-1]": "'high'" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + diagnosis: diabetes_type2 + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + performance: "[perf]" + traceData: ~ + patientCharacteristics: + id: patientCharacteristics + input: + base_treatment: oral_medication + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + name: patientFactors + order: + "$serde_json::private::Number": "2" + output: + base_treatment: oral_medication + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + dosage_modification: standard_elderly + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + patient_risk_category: moderate + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + patient.age: + "$serde_json::private::Number": "67" + patient.is_pregnant: "no" + rule: + _id: pc2 + "patient.age[i2-1]": ">= 65" + "patient.is_pregnant[i2-2]": "'no'" + protocolIntensity: + id: protocolIntensity + input: + base_treatment: oral_medication + comorbidity_risk_level: high + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + dosage_modification: standard_elderly + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + patient_risk_category: moderate + risk_adjustment: modified_treatment + name: intensityDetermination + order: + "$serde_json::private::Number": "4" + output: + base_treatment: oral_medication + comorbidity_risk_level: high + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + dosage_modification: standard_elderly + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + patient_risk_category: moderate + protocol_intensity: intensive + risk_adjustment: modified_treatment + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + comorbidity_risk_level: high + rule: + _id: pi2 + "comorbidity_risk_level[i4-1]": "'high'" + riskFactors: + id: riskFactors + input: + base_treatment: oral_medication + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + dosage_modification: standard_elderly + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + patient_risk_category: moderate + name: comorbidityEvaluation + order: + "$serde_json::private::Number": "3" + output: + base_treatment: oral_medication + comorbidity_risk_level: high + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + dosage_modification: standard_elderly + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + patient_risk_category: moderate + risk_adjustment: modified_treatment + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + patient.has_comorbidities: "yes" + patient.previous_adverse_reaction: "no" + rule: + _id: rf2 + "patient.has_comorbidities[i3-1]": "'yes'" + "patient.previous_adverse_reaction[i3-2]": "'no'" + treatmentProtocol: + id: treatmentProtocol + input: + base_treatment: oral_medication + comorbidity_risk_level: high + diagnosis: diabetes_type2 + diagnosis_severity: moderate_diabetes + dosage_modification: standard_elderly + follow_up_schedule: bi-weekly + measurement_value: + "$serde_json::private::Number": "8.2" + patient: + age: + "$serde_json::private::Number": "67" + has_comorbidities: "yes" + is_pregnant: "no" + previous_adverse_reaction: "no" + patient_risk_category: moderate + protocol_intensity: intensive + risk_adjustment: modified_treatment + name: finalTreatmentSelection + order: + "$serde_json::private::Number": "6" + output: + protocol_name: oral_medication_moderate + treatment_protocol: + base_treatment: oral_medication + dosage_instruction: standard_elderly + follow_up_frequency: bi-weekly + protocol_id: oral_medication_moderate_intensive + protocol_intensity: intensive + risk_adjustment: modified_treatment + severity_level: moderate_diabetes + performance: "[perf]" + traceData: + protocol_name: + result: "\"oral_medication_moderate\"" + treatment_protocol: + result: "{\"follow_up_frequency\":\"bi-weekly\",\"risk_adjustment\":\"modified_treatment\",\"base_treatment\":\"oral_medication\",\"protocol_intensity\":\"intensive\",\"dosage_instruction\":\"standard_elderly\",\"protocol_id\":\"oral_medication_moderate_intensive\",\"severity_level\":\"moderate_diabetes\"}" diff --git a/core/engine/tests/snapshots/engine__clinical-trial-eligibility-screener_0.snap b/core/engine/tests/snapshots/engine__clinical-trial-eligibility-screener_0.snap new file mode 100644 index 00000000..465d70f5 --- /dev/null +++ b/core/engine/tests/snapshots/engine__clinical-trial-eligibility-screener_0.snap @@ -0,0 +1,569 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + decisionSummary: Patient is not eligible for clinical trial + eligibilityReasons: + - flag: true + reason: Diagnosis matches trial criteria + - flag: false + reason: Excluded comorbidity present + - flag: false + reason: Too many prior treatments + - flag: false + reason: Patient taking excluded medications + - flag: false + reason: Stage IV patients excluded from trial + - flag: true + reason: Age within eligible range + failedCriteria: + - comorbidity + - priorTreatment + - medication + - stage + isEligible: false +trace: + ageEligibility: + id: ageEligibility + input: + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + name: ageEligibility + order: + "$serde_json::private::Number": "4" + output: + eligibility: + age: + flag: true + reason: Age within eligible range + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + patient.age: + "$serde_json::private::Number": "68" + rule: + _id: rule2 + "patient.age[age]": "" + comorbidityEligibility: + id: comorbidityEligibility + input: + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + name: comorbidityEligibility + order: + "$serde_json::private::Number": "6" + output: + eligibility: + comorbidity: + flag: false + reason: Excluded comorbidity present + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + "patient.comorbidities ?? []": + - autoimmune_disease + - COPD + rule: + _id: rule1 + "patient.comorbidities ?? [][comorbidities]": "some($, # in ['autoimmune_disease', 'heart_failure', 'uncontrolled_diabetes'])" + diagnosisEligibility: + id: diagnosisEligibility + input: + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + name: diagnosisEligibility + order: + "$serde_json::private::Number": "1" + output: + eligibility: + diagnosis: + flag: true + reason: Diagnosis matches trial criteria + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + patient.diagnosis: lung_cancer + rule: + _id: rule1 + "patient.diagnosis[diagnosis]": "'breast_cancer', 'lung_cancer', 'colorectal_cancer'" + diseaseStageEligibility: + id: diseaseStageEligibility + input: + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + name: diseaseStageEligibility + order: + "$serde_json::private::Number": "2" + output: + eligibility: + stage: + flag: false + reason: Stage IV patients excluded from trial + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + patient.diseaseStage: IV + rule: + _id: rule2 + "patient.diseaseStage[stage]": "'IV'" + eligibilitySummary: + id: eligibilitySummary + input: + eligibility: + age: + flag: true + reason: Age within eligible range + comorbidity: + flag: false + reason: Excluded comorbidity present + diagnosis: + flag: true + reason: Diagnosis matches trial criteria + medication: + flag: false + reason: Patient taking excluded medications + priorTreatment: + flag: false + reason: Too many prior treatments + stage: + flag: false + reason: Stage IV patients excluded from trial + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + name: eligibilitySummary + order: + "$serde_json::private::Number": "7" + output: + decisionSummary: Patient is not eligible for clinical trial + eligibilityReasons: + - flag: true + reason: Diagnosis matches trial criteria + - flag: false + reason: Excluded comorbidity present + - flag: false + reason: Too many prior treatments + - flag: false + reason: Patient taking excluded medications + - flag: false + reason: Stage IV patients excluded from trial + - flag: true + reason: Age within eligible range + failedCriteria: + - comorbidity + - priorTreatment + - medication + - stage + isEligible: false + performance: "[perf]" + traceData: + decisionSummary: + result: "\"Patient is not eligible for clinical trial\"" + eligibilityReasons: + result: "[{\"reason\":\"Diagnosis matches trial criteria\",\"flag\":true},{\"reason\":\"Excluded comorbidity present\",\"flag\":false},{\"flag\":false,\"reason\":\"Too many prior treatments\"},{\"flag\":false,\"reason\":\"Patient taking excluded medications\"},{\"reason\":\"Stage IV patients excluded from trial\",\"flag\":false},{\"reason\":\"Age within eligible range\",\"flag\":true}]" + failedCriteria: + result: "[\"comorbidity\",\"priorTreatment\",\"medication\",\"stage\"]" + isEligible: + result: "false" + inputNode: + id: inputNode + input: ~ + name: patient + order: + "$serde_json::private::Number": "0" + output: + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: ~ + medicationEligibility: + id: medicationEligibility + input: + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + name: medicationEligibility + order: + "$serde_json::private::Number": "3" + output: + eligibility: + medication: + flag: false + reason: Patient taking excluded medications + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + "patient.currentMedications ?? []": + - immunosuppressants + - albuterol + - omeprazole + rule: + _id: rule1 + "patient.currentMedications ?? [][medications]": "some($, # in ['immunosuppressants', 'anticancer_agents', 'corticosteroids'])" + priorTreatmentEligibility: + id: priorTreatmentEligibility + input: + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + name: priorTreatmentEligibility + order: + "$serde_json::private::Number": "5" + output: + eligibility: + priorTreatment: + flag: false + reason: Too many prior treatments + patient: + age: + "$serde_json::private::Number": "68" + comorbidities: + - autoimmune_disease + - COPD + currentMedications: + - immunosuppressants + - albuterol + - omeprazole + diagnosis: lung_cancer + diseaseStage: IV + id: P67890 + lastLabResults: + creatinine: + "$serde_json::private::Number": "1.2" + hgb: + "$serde_json::private::Number": "10.9" + plt: + "$serde_json::private::Number": "150" + wbc: + "$serde_json::private::Number": "3.8" + name: John Smith + priorTreatments: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + patient.priorTreatments: + "$serde_json::private::Number": "3" + rule: + _id: rule1 + "patient.priorTreatments[priorTreatments]": "> 2" diff --git a/core/engine/tests/snapshots/engine__company-analysis_0.snap b/core/engine/tests/snapshots/engine__company-analysis_0.snap new file mode 100644 index 00000000..fbdfec4a --- /dev/null +++ b/core/engine/tests/snapshots/engine__company-analysis_0.snap @@ -0,0 +1,168 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + flag: + companyType: green + country: green + turnover: red + overall: red +trace: + 46fbad36-4bbe-44ac-833f-d30e0d37d8d7: + id: 46fbad36-4bbe-44ac-833f-d30e0d37d8d7 + input: + companyInformation: + country: + code: US + experian: + legalStatus: LTD + name: Turnover + order: + "$serde_json::private::Number": "3" + output: + flag: + turnover: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + companyInformation.country.code: US + companyInformation.financialDetails.turnover: ~ + rule: + _id: SY7uwJEPqS + "companyInformation.country.code[2Zxqan3BtC]": "" + "companyInformation.financialDetails.turnover[6xj5CMIFv9]": "" + 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a: + id: 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + companyInformation: + country: + code: US + experian: + legalStatus: LTD + performance: "[perf]" + traceData: ~ + 86ce04c9-b4dd-4513-ae2b-7f585ceb224a: + id: 86ce04c9-b4dd-4513-ae2b-7f585ceb224a + input: + amber: + "$serde_json::private::Number": "0" + critical: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "1" + name: Overall + order: + "$serde_json::private::Number": "5" + output: + overall: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + amber: + "$serde_json::private::Number": "0" + critical: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "1" + rule: + _id: UGrT2iHE61 + "amber[QJttqyV2FB]": "" + "critical[KsBwLhAedP]": "" + "green[iFQl1CKB5S]": "" + "red[AczIUwvClr]": "> 0" + 95aa8f3c-f371-4e48-beb3-0b5775d2a814: + id: 95aa8f3c-f371-4e48-beb3-0b5775d2a814 + input: + flag: + companyType: green + country: green + turnover: red + overall: red + name: Response + order: + "$serde_json::private::Number": "6" + output: ~ + performance: "[perf]" + traceData: ~ + abaaa033-5516-440c-b211-35f1d616ad9f: + id: abaaa033-5516-440c-b211-35f1d616ad9f + input: + companyInformation: + country: + code: US + experian: + legalStatus: LTD + name: Country + order: + "$serde_json::private::Number": "1" + output: + flag: + country: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + companyInformation.country.code: US + rule: + _id: TOi2qECISd + "companyInformation.country.code[z87lDk-Xar]": "\"US\",\"IE\",\"GB\",\"CA\", \"MX\"" + af6cdac4-2019-4a0f-9715-2ecfb27e0bfc: + id: af6cdac4-2019-4a0f-9715-2ecfb27e0bfc + input: + flag: + companyType: green + country: green + turnover: red + name: Overall Mapper + order: + "$serde_json::private::Number": "4" + output: + amber: + "$serde_json::private::Number": "0" + critical: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: + log: [] + d6925cde-b3c9-4b7f-8652-7380dacea6a4: + id: d6925cde-b3c9-4b7f-8652-7380dacea6a4 + input: + companyInformation: + country: + code: US + experian: + legalStatus: LTD + name: Company Type + order: + "$serde_json::private::Number": "2" + output: + flag: + companyType: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + companyInformation.experian.legalStatus: LTD + rule: + _id: D8T0xuyYLC + "companyInformation.experian.legalStatus[nd30YgUKve]": "\"INC\",\"LTD\",\"LLC\"" diff --git a/core/engine/tests/snapshots/engine__company-analysis_1.snap b/core/engine/tests/snapshots/engine__company-analysis_1.snap new file mode 100644 index 00000000..755eb896 --- /dev/null +++ b/core/engine/tests/snapshots/engine__company-analysis_1.snap @@ -0,0 +1,181 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + flag: + companyType: green + country: amber + turnover: amber + overall: amber +trace: + 46fbad36-4bbe-44ac-833f-d30e0d37d8d7: + id: 46fbad36-4bbe-44ac-833f-d30e0d37d8d7 + input: + companyInformation: + country: + code: FR + experian: + legalStatus: LTD + financialDetails: + turnover: + "$serde_json::private::Number": "250000" + name: Turnover + order: + "$serde_json::private::Number": "3" + output: + flag: + turnover: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + companyInformation.country.code: FR + companyInformation.financialDetails.turnover: + "$serde_json::private::Number": "250000" + rule: + _id: lqBoqkvWHA + "companyInformation.country.code[2Zxqan3BtC]": "" + "companyInformation.financialDetails.turnover[6xj5CMIFv9]": "[200_000..1_000_000]" + 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a: + id: 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + companyInformation: + country: + code: FR + experian: + legalStatus: LTD + financialDetails: + turnover: + "$serde_json::private::Number": "250000" + performance: "[perf]" + traceData: ~ + 86ce04c9-b4dd-4513-ae2b-7f585ceb224a: + id: 86ce04c9-b4dd-4513-ae2b-7f585ceb224a + input: + amber: + "$serde_json::private::Number": "2" + critical: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "1" + red: + "$serde_json::private::Number": "0" + name: Overall + order: + "$serde_json::private::Number": "5" + output: + overall: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + amber: + "$serde_json::private::Number": "2" + critical: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "1" + red: + "$serde_json::private::Number": "0" + rule: + _id: SBBO_aWujh + "amber[QJttqyV2FB]": "> 1" + "critical[KsBwLhAedP]": "" + "green[iFQl1CKB5S]": "" + "red[AczIUwvClr]": "" + 95aa8f3c-f371-4e48-beb3-0b5775d2a814: + id: 95aa8f3c-f371-4e48-beb3-0b5775d2a814 + input: + flag: + companyType: green + country: amber + turnover: amber + overall: amber + name: Response + order: + "$serde_json::private::Number": "6" + output: ~ + performance: "[perf]" + traceData: ~ + abaaa033-5516-440c-b211-35f1d616ad9f: + id: abaaa033-5516-440c-b211-35f1d616ad9f + input: + companyInformation: + country: + code: FR + experian: + legalStatus: LTD + financialDetails: + turnover: + "$serde_json::private::Number": "250000" + name: Country + order: + "$serde_json::private::Number": "1" + output: + flag: + country: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + companyInformation.country.code: FR + rule: + _id: aGPqCdh2tU + "companyInformation.country.code[z87lDk-Xar]": "\"FR\", \"DE\"" + af6cdac4-2019-4a0f-9715-2ecfb27e0bfc: + id: af6cdac4-2019-4a0f-9715-2ecfb27e0bfc + input: + flag: + companyType: green + country: amber + turnover: amber + name: Overall Mapper + order: + "$serde_json::private::Number": "4" + output: + amber: + "$serde_json::private::Number": "2" + critical: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "1" + red: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + log: [] + d6925cde-b3c9-4b7f-8652-7380dacea6a4: + id: d6925cde-b3c9-4b7f-8652-7380dacea6a4 + input: + companyInformation: + country: + code: FR + experian: + legalStatus: LTD + financialDetails: + turnover: + "$serde_json::private::Number": "250000" + name: Company Type + order: + "$serde_json::private::Number": "2" + output: + flag: + companyType: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + companyInformation.experian.legalStatus: LTD + rule: + _id: D8T0xuyYLC + "companyInformation.experian.legalStatus[nd30YgUKve]": "\"INC\",\"LTD\",\"LLC\"" diff --git a/core/engine/tests/snapshots/engine__company-analysis_2.snap b/core/engine/tests/snapshots/engine__company-analysis_2.snap new file mode 100644 index 00000000..3c328867 --- /dev/null +++ b/core/engine/tests/snapshots/engine__company-analysis_2.snap @@ -0,0 +1,181 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + flag: + companyType: green + country: amber + turnover: green + overall: green +trace: + 46fbad36-4bbe-44ac-833f-d30e0d37d8d7: + id: 46fbad36-4bbe-44ac-833f-d30e0d37d8d7 + input: + companyInformation: + country: + code: FR + experian: + legalStatus: LTD + financialDetails: + turnover: + "$serde_json::private::Number": "10000001" + name: Turnover + order: + "$serde_json::private::Number": "3" + output: + flag: + turnover: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + companyInformation.country.code: FR + companyInformation.financialDetails.turnover: + "$serde_json::private::Number": "10000001" + rule: + _id: fJxWqBVUNk + "companyInformation.country.code[2Zxqan3BtC]": "" + "companyInformation.financialDetails.turnover[6xj5CMIFv9]": "> 1_000_000" + 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a: + id: 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + companyInformation: + country: + code: FR + experian: + legalStatus: LTD + financialDetails: + turnover: + "$serde_json::private::Number": "10000001" + performance: "[perf]" + traceData: ~ + 86ce04c9-b4dd-4513-ae2b-7f585ceb224a: + id: 86ce04c9-b4dd-4513-ae2b-7f585ceb224a + input: + amber: + "$serde_json::private::Number": "1" + critical: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "0" + name: Overall + order: + "$serde_json::private::Number": "5" + output: + overall: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + amber: + "$serde_json::private::Number": "1" + critical: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "0" + rule: + _id: N2jO9BnXHY + "amber[QJttqyV2FB]": "" + "critical[KsBwLhAedP]": "" + "green[iFQl1CKB5S]": "" + "red[AczIUwvClr]": "" + 95aa8f3c-f371-4e48-beb3-0b5775d2a814: + id: 95aa8f3c-f371-4e48-beb3-0b5775d2a814 + input: + flag: + companyType: green + country: amber + turnover: green + overall: green + name: Response + order: + "$serde_json::private::Number": "6" + output: ~ + performance: "[perf]" + traceData: ~ + abaaa033-5516-440c-b211-35f1d616ad9f: + id: abaaa033-5516-440c-b211-35f1d616ad9f + input: + companyInformation: + country: + code: FR + experian: + legalStatus: LTD + financialDetails: + turnover: + "$serde_json::private::Number": "10000001" + name: Country + order: + "$serde_json::private::Number": "1" + output: + flag: + country: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + companyInformation.country.code: FR + rule: + _id: aGPqCdh2tU + "companyInformation.country.code[z87lDk-Xar]": "\"FR\", \"DE\"" + af6cdac4-2019-4a0f-9715-2ecfb27e0bfc: + id: af6cdac4-2019-4a0f-9715-2ecfb27e0bfc + input: + flag: + companyType: green + country: amber + turnover: green + name: Overall Mapper + order: + "$serde_json::private::Number": "4" + output: + amber: + "$serde_json::private::Number": "1" + critical: + "$serde_json::private::Number": "0" + green: + "$serde_json::private::Number": "2" + red: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + log: [] + d6925cde-b3c9-4b7f-8652-7380dacea6a4: + id: d6925cde-b3c9-4b7f-8652-7380dacea6a4 + input: + companyInformation: + country: + code: FR + experian: + legalStatus: LTD + financialDetails: + turnover: + "$serde_json::private::Number": "10000001" + name: Company Type + order: + "$serde_json::private::Number": "2" + output: + flag: + companyType: green + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + companyInformation.experian.legalStatus: LTD + rule: + _id: D8T0xuyYLC + "companyInformation.experian.legalStatus[nd30YgUKve]": "\"INC\",\"LTD\",\"LLC\"" diff --git a/core/engine/tests/snapshots/engine__credit-limit-adjustment_0.snap b/core/engine/tests/snapshots/engine__credit-limit-adjustment_0.snap new file mode 100644 index 00000000..bc61d52e --- /dev/null +++ b/core/engine/tests/snapshots/engine__credit-limit-adjustment_0.snap @@ -0,0 +1,527 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + recommendation: + amount_change: + "$serde_json::private::Number": "1500" + new_credit_limit: + "$serde_json::private::Number": "6500" +trace: + creditLimitRecommendationNode: + id: creditLimitRecommendationNode + input: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + financial_behavior_rating: excellent + financial_behavior_score: + "$serde_json::private::Number": "25" + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + utilization_rating: low + utilization_score: + "$serde_json::private::Number": "25" + total_adjustment_score: + "$serde_json::private::Number": "80" + name: credit_limit_recommendation + order: + "$serde_json::private::Number": "5" + output: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + financial_behavior_rating: excellent + financial_behavior_score: + "$serde_json::private::Number": "25" + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + utilization_rating: low + utilization_score: + "$serde_json::private::Number": "25" + recommendation: + justification: Significant increase recommended based on excellent history and behavior. + percent_change: + "$serde_json::private::Number": "30" + total_adjustment_score: + "$serde_json::private::Number": "80" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + total_adjustment_score: + "$serde_json::private::Number": "80" + rule: + _id: rule1 + "total_adjustment_score[i4-1]": "> 50" + finalCalculationNode: + id: finalCalculationNode + input: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + financial_behavior_rating: excellent + financial_behavior_score: + "$serde_json::private::Number": "25" + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + utilization_rating: low + utilization_score: + "$serde_json::private::Number": "25" + recommendation: + justification: Significant increase recommended based on excellent history and behavior. + percent_change: + "$serde_json::private::Number": "30" + total_adjustment_score: + "$serde_json::private::Number": "80" + name: calculate_final_amounts + order: + "$serde_json::private::Number": "6" + output: + recommendation: + amount_change: + "$serde_json::private::Number": "1500" + new_credit_limit: + "$serde_json::private::Number": "6500" + performance: "[perf]" + traceData: + recommendation.amount_change: + result: "1500" + recommendation.new_credit_limit: + result: "6500" + financialBehaviorNode: + id: financialBehaviorNode + input: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + utilization_rating: low + utilization_score: + "$serde_json::private::Number": "25" + name: financial_behavior_evaluation + order: + "$serde_json::private::Number": "3" + output: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + financial_behavior_rating: excellent + financial_behavior_score: + "$serde_json::private::Number": "25" + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + utilization_rating: low + utilization_score: + "$serde_json::private::Number": "25" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + account.financial_behavior.credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + account.financial_behavior.income_verified: true + account.financial_behavior.years_with_institution: + "$serde_json::private::Number": "4" + rule: + _id: rule1 + "account.financial_behavior.credit_inquiries_last_12_months[i3-1]": "< 1" + "account.financial_behavior.income_verified[i3-3]": "true" + "account.financial_behavior.years_with_institution[i3-2]": ">= 3" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + performance: "[perf]" + traceData: ~ + paymentHistoryNode: + id: paymentHistoryNode + input: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + name: payment_history_evaluation + order: + "$serde_json::private::Number": "1" + output: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + account.payment_history.late_payments_last_12_months: + "$serde_json::private::Number": "0" + account.payment_history.on_time_payment_percentage: + "$serde_json::private::Number": "98" + rule: + _id: rule1 + "account.payment_history.late_payments_last_12_months[i1-2]": "<= 0" + "account.payment_history.on_time_payment_percentage[i1-1]": ">= 95" + scoreCalculationNode: + id: scoreCalculationNode + input: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + financial_behavior_rating: excellent + financial_behavior_score: + "$serde_json::private::Number": "25" + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + utilization_rating: low + utilization_score: + "$serde_json::private::Number": "25" + name: calculate_total_score + order: + "$serde_json::private::Number": "4" + output: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + financial_behavior_rating: excellent + financial_behavior_score: + "$serde_json::private::Number": "25" + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + utilization_rating: low + utilization_score: + "$serde_json::private::Number": "25" + total_adjustment_score: + "$serde_json::private::Number": "80" + performance: "[perf]" + traceData: + total_adjustment_score: + result: "80" + utilizationNode: + id: utilizationNode + input: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + name: utilization_evaluation + order: + "$serde_json::private::Number": "2" + output: + account: + current_credit_limit: + "$serde_json::private::Number": "5000" + customer_id: CUST10025 + financial_behavior: + credit_inquiries_last_12_months: + "$serde_json::private::Number": "0" + has_other_products: true + income_verified: true + years_with_institution: + "$serde_json::private::Number": "4" + payment_history: + late_payments_last_12_months: + "$serde_json::private::Number": "0" + on_time_payment_percentage: + "$serde_json::private::Number": "98" + total_payments: + "$serde_json::private::Number": "24" + utilization: + average_last_6_months: + "$serde_json::private::Number": "40" + current_percentage: + "$serde_json::private::Number": "25" + highest_balance: + "$serde_json::private::Number": "2800" + evaluation: + payment_history_rating: excellent + payment_history_score: + "$serde_json::private::Number": "30" + utilization_rating: low + utilization_score: + "$serde_json::private::Number": "25" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + account.utilization.average_last_6_months: + "$serde_json::private::Number": "40" + account.utilization.current_percentage: + "$serde_json::private::Number": "25" + rule: + _id: rule1 + "account.utilization.average_last_6_months[i2-2]": "< 50" + "account.utilization.current_percentage[i2-1]": "< 30" diff --git a/core/engine/tests/snapshots/engine__customer-eligibility-engine_0.snap b/core/engine/tests/snapshots/engine__customer-eligibility-engine_0.snap new file mode 100644 index 00000000..3fd24eeb --- /dev/null +++ b/core/engine/tests/snapshots/engine__customer-eligibility-engine_0.snap @@ -0,0 +1,467 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + features: + conciergeService: false + contentStreaming: true + internationalRoaming: true + message: Most premium features available based on gold status. + prioritySupport: true +trace: + accountStatus: + id: accountStatus + input: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + name: evaluateAccountStatus + order: + "$serde_json::private::Number": "1" + output: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + eligibility: + accountStatus: excellent + goodStanding: true + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + accountInfo.accountAge: + "$serde_json::private::Number": "28" + accountInfo.contractStatus: pending_renewal + accountInfo.paymentHistory: excellent + rule: + _id: r1 + "accountInfo.accountAge[i1]": ">= 24" + "accountInfo.contractStatus[i3]": "" + "accountInfo.paymentHistory[i2]": "'excellent'" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + performance: "[perf]" + traceData: ~ + loyaltyTier: + id: loyaltyTier + input: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + eligibility: + accountStatus: excellent + goodStanding: true + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + name: determineLoyaltyTier + order: + "$serde_json::private::Number": "2" + output: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + eligibility: + accountStatus: excellent + goodStanding: true + loyaltyDiscountPercent: + "$serde_json::private::Number": "15" + loyaltyTier: gold + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + accountInfo.accountAge: + "$serde_json::private::Number": "28" + accountInfo.monthlySpend: + "$serde_json::private::Number": "95" + eligibility.accountStatus: excellent + rule: + _id: r2 + "accountInfo.accountAge[i1]": ">= 24" + "accountInfo.monthlySpend[i2]": ">= 80" + "eligibility.accountStatus[i3]": "'excellent', 'good'" + premiumFeatures: + id: premiumFeatures + input: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + eligibility: + accountStatus: excellent + canUpgrade: true + earlyUpgradeEligible: true + goodStanding: true + loyaltyDiscountPercent: + "$serde_json::private::Number": "15" + loyaltyTier: gold + offerCount: + "$serde_json::private::Number": "5" + premiumPlanEligible: true + specialOffers: + dataBooster: true + deviceUpgrade: true + familyPlan: true + internationalBundle: true + loyaltyReward: true + upgradeMessage: High-priority upgrade eligible. Offers for all plan categories. + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + name: determinePremiumFeatures + order: + "$serde_json::private::Number": "5" + output: + features: + conciergeService: false + contentStreaming: true + internationalRoaming: true + message: Most premium features available based on gold status. + prioritySupport: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + eligibility.goodStanding: true + eligibility.loyaltyTier: gold + eligibility.offerCount: + "$serde_json::private::Number": "5" + rule: + _id: r2 + "eligibility.goodStanding[i2]": "true" + "eligibility.loyaltyTier[i1]": "['gold']" + "eligibility.offerCount[i3]": ">= 2" + specialOffers: + id: specialOffers + input: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + eligibility: + accountStatus: excellent + canUpgrade: true + earlyUpgradeEligible: true + goodStanding: true + loyaltyDiscountPercent: + "$serde_json::private::Number": "15" + loyaltyTier: gold + premiumPlanEligible: true + upgradeMessage: High-priority upgrade eligible. Offers for all plan categories. + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + name: determineSpecialOffers + order: + "$serde_json::private::Number": "4" + output: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + eligibility: + accountStatus: excellent + canUpgrade: true + earlyUpgradeEligible: true + goodStanding: true + loyaltyDiscountPercent: + "$serde_json::private::Number": "15" + loyaltyTier: gold + offerCount: + "$serde_json::private::Number": "5" + premiumPlanEligible: true + specialOffers: + dataBooster: true + deviceUpgrade: true + familyPlan: true + internationalBundle: true + loyaltyReward: true + upgradeMessage: High-priority upgrade eligible. Offers for all plan categories. + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + performance: "[perf]" + traceData: + eligibility.offerCount: + result: "5" + eligibility.specialOffers: + result: "{\"dataBooster\":true,\"deviceUpgrade\":true,\"internationalBundle\":true,\"familyPlan\":true,\"loyaltyReward\":true}" + upgradeEligibility: + id: upgradeEligibility + input: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + eligibility: + accountStatus: excellent + goodStanding: true + loyaltyDiscountPercent: + "$serde_json::private::Number": "15" + loyaltyTier: gold + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + name: determineUpgradeEligibility + order: + "$serde_json::private::Number": "3" + output: + accountInfo: + accountAge: + "$serde_json::private::Number": "28" + contractStatus: pending_renewal + currentPlan: Family Premium 50GB + monthlySpend: + "$serde_json::private::Number": "95" + paymentHistory: excellent + customerId: CUST12345 + customerProfile: + devices: + - iPhone 14 + - iPad Air + - Apple Watch + location: "Seattle, WA" + previousComplaints: + "$serde_json::private::Number": "0" + segment: consumer + eligibility: + accountStatus: excellent + canUpgrade: true + earlyUpgradeEligible: true + goodStanding: true + loyaltyDiscountPercent: + "$serde_json::private::Number": "15" + loyaltyTier: gold + premiumPlanEligible: true + upgradeMessage: High-priority upgrade eligible. Offers for all plan categories. + usageStats: + callMinutes: + "$serde_json::private::Number": "350" + dataUsageGB: + "$serde_json::private::Number": "42.5" + dataUtilizationPercent: + "$serde_json::private::Number": "85" + textMessages: + "$serde_json::private::Number": "1250" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + eligibility.goodStanding: true + eligibility.loyaltyTier: gold + rule: + _id: r1 + "eligibility.goodStanding[i1]": "true" + "eligibility.loyaltyTier[i2]": "['platinum', 'gold']" diff --git a/core/engine/tests/snapshots/engine__customer-lifetime-value_0.snap b/core/engine/tests/snapshots/engine__customer-lifetime-value_0.snap new file mode 100644 index 00000000..c6cdc89e --- /dev/null +++ b/core/engine/tests/snapshots/engine__customer-lifetime-value_0.snap @@ -0,0 +1,238 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + acquisitionCostRatio: + "$serde_json::private::Number": "0.0095436036647438072616219885" + adjustedLTV: + "$serde_json::private::Number": "15567.333333333333333333333334" + averageOrderValue: + "$serde_json::private::Number": "168.4" + basicLTV: + "$serde_json::private::Number": "15717.333333333333333333333334" + customer: + acquisitionChannel: paid_search + acquisitionCost: + "$serde_json::private::Number": "150" + id: CUST-12345 + name: John Doe + segment: retail + customerInsights: + recommendedStrategy: "High-touch service, premium offers, exclusive events" + tier: platinum + customerLifetimeMonths: + "$serde_json::private::Number": "80" + grossMargin: + "$serde_json::private::Number": "0.35" + purchaseFrequency: + "$serde_json::private::Number": "3.3333333333333333333333333336" + purchaseHistory: + averageGrossMarginPercent: + "$serde_json::private::Number": "35" + customerDurationMonths: + "$serde_json::private::Number": "18" + orderValues: + - "$serde_json::private::Number": "120" + - "$serde_json::private::Number": "89" + - "$serde_json::private::Number": "245" + - "$serde_json::private::Number": "78" + - "$serde_json::private::Number": "310" + retentionRate: + "$serde_json::private::Number": "85" +trace: + dt1: + id: dt1 + input: + acquisitionCostRatio: + "$serde_json::private::Number": "0.0095436036647438072616219885" + adjustedLTV: + "$serde_json::private::Number": "15567.333333333333333333333334" + averageOrderValue: + "$serde_json::private::Number": "168.4" + basicLTV: + "$serde_json::private::Number": "15717.333333333333333333333334" + customer: + acquisitionChannel: paid_search + acquisitionCost: + "$serde_json::private::Number": "150" + id: CUST-12345 + name: John Doe + segment: retail + customerLifetimeMonths: + "$serde_json::private::Number": "80" + grossMargin: + "$serde_json::private::Number": "0.35" + purchaseFrequency: + "$serde_json::private::Number": "3.3333333333333333333333333336" + purchaseHistory: + averageGrossMarginPercent: + "$serde_json::private::Number": "35" + customerDurationMonths: + "$serde_json::private::Number": "18" + orderValues: + - "$serde_json::private::Number": "120" + - "$serde_json::private::Number": "89" + - "$serde_json::private::Number": "245" + - "$serde_json::private::Number": "78" + - "$serde_json::private::Number": "310" + retentionRate: + "$serde_json::private::Number": "85" + name: customer_segmentation + order: + "$serde_json::private::Number": "2" + output: + acquisitionCostRatio: + "$serde_json::private::Number": "0.0095436036647438072616219885" + adjustedLTV: + "$serde_json::private::Number": "15567.333333333333333333333334" + averageOrderValue: + "$serde_json::private::Number": "168.4" + basicLTV: + "$serde_json::private::Number": "15717.333333333333333333333334" + customer: + acquisitionChannel: paid_search + acquisitionCost: + "$serde_json::private::Number": "150" + id: CUST-12345 + name: John Doe + segment: retail + customerInsights: + recommendedStrategy: "High-touch service, premium offers, exclusive events" + tier: platinum + customerLifetimeMonths: + "$serde_json::private::Number": "80" + grossMargin: + "$serde_json::private::Number": "0.35" + purchaseFrequency: + "$serde_json::private::Number": "3.3333333333333333333333333336" + purchaseHistory: + averageGrossMarginPercent: + "$serde_json::private::Number": "35" + customerDurationMonths: + "$serde_json::private::Number": "18" + orderValues: + - "$serde_json::private::Number": "120" + - "$serde_json::private::Number": "89" + - "$serde_json::private::Number": "245" + - "$serde_json::private::Number": "78" + - "$serde_json::private::Number": "310" + retentionRate: + "$serde_json::private::Number": "85" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + adjustedLTV: + "$serde_json::private::Number": "15567.333333333333333333333334" + rule: + _id: r1-1 + "adjustedLTV[i1-1]": "> 2000" + ex1: + id: ex1 + input: + customer: + acquisitionChannel: paid_search + acquisitionCost: + "$serde_json::private::Number": "150" + id: CUST-12345 + name: John Doe + segment: retail + purchaseHistory: + averageGrossMarginPercent: + "$serde_json::private::Number": "35" + customerDurationMonths: + "$serde_json::private::Number": "18" + orderValues: + - "$serde_json::private::Number": "120" + - "$serde_json::private::Number": "89" + - "$serde_json::private::Number": "245" + - "$serde_json::private::Number": "78" + - "$serde_json::private::Number": "310" + retentionRate: + "$serde_json::private::Number": "85" + name: clv_calculation + order: + "$serde_json::private::Number": "1" + output: + acquisitionCostRatio: + "$serde_json::private::Number": "0.0095436036647438072616219885" + adjustedLTV: + "$serde_json::private::Number": "15567.333333333333333333333334" + averageOrderValue: + "$serde_json::private::Number": "168.4" + basicLTV: + "$serde_json::private::Number": "15717.333333333333333333333334" + customer: + acquisitionChannel: paid_search + acquisitionCost: + "$serde_json::private::Number": "150" + id: CUST-12345 + name: John Doe + segment: retail + customerLifetimeMonths: + "$serde_json::private::Number": "80" + grossMargin: + "$serde_json::private::Number": "0.35" + purchaseFrequency: + "$serde_json::private::Number": "3.3333333333333333333333333336" + purchaseHistory: + averageGrossMarginPercent: + "$serde_json::private::Number": "35" + customerDurationMonths: + "$serde_json::private::Number": "18" + orderValues: + - "$serde_json::private::Number": "120" + - "$serde_json::private::Number": "89" + - "$serde_json::private::Number": "245" + - "$serde_json::private::Number": "78" + - "$serde_json::private::Number": "310" + retentionRate: + "$serde_json::private::Number": "85" + performance: "[perf]" + traceData: + acquisitionCostRatio: + result: "0.0095436036647438072616219885" + adjustedLTV: + result: "15567.333333333333333333333334" + averageOrderValue: + result: "168.4" + basicLTV: + result: "15717.333333333333333333333334" + customerLifetimeMonths: + result: "80" + grossMargin: + result: "0.35" + purchaseFrequency: + result: "3.3333333333333333333333333336" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + acquisitionChannel: paid_search + acquisitionCost: + "$serde_json::private::Number": "150" + id: CUST-12345 + name: John Doe + segment: retail + purchaseHistory: + averageGrossMarginPercent: + "$serde_json::private::Number": "35" + customerDurationMonths: + "$serde_json::private::Number": "18" + orderValues: + - "$serde_json::private::Number": "120" + - "$serde_json::private::Number": "89" + - "$serde_json::private::Number": "245" + - "$serde_json::private::Number": "78" + - "$serde_json::private::Number": "310" + retentionRate: + "$serde_json::private::Number": "85" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__customer-onboarding-kyc-verification_0.snap b/core/engine/tests/snapshots/engine__customer-onboarding-kyc-verification_0.snap new file mode 100644 index 00000000..7ba278c7 --- /dev/null +++ b/core/engine/tests/snapshots/engine__customer-onboarding-kyc-verification_0.snap @@ -0,0 +1,648 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + nextSteps: Onboarding approved + requiredActionsCount: + "$serde_json::private::Number": "0" + requirements: + addressVerification: false + enhancedMonitoring: false + faceVerification: false + sourceOfFunds: false + verificationStatus: approved +trace: + additionalChecks: + id: additionalChecks + input: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + dueDiligenceLevel: standard + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + isSanctioned: false + requiresEDD: false + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + documentVerificationStatus: standard + isDocumentVerified: true + requiresAdditionalVerification: false + watchlist: + adverseMediaMatch: false + message: No watchlist hits found + passed: true + pepListMatch: false + sanctionsMatch: false + status: pass + name: additionalChecks + order: + "$serde_json::private::Number": "5" + output: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + dueDiligenceLevel: standard + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + isSanctioned: false + requirements: + addressVerification: false + enhancedMonitoring: false + faceVerification: false + sourceOfFunds: false + requiresEDD: false + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + documentVerificationStatus: standard + isDocumentVerified: true + requiresAdditionalVerification: false + watchlist: + adverseMediaMatch: false + message: No watchlist hits found + passed: true + pepListMatch: false + sanctionsMatch: false + status: pass + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + assessment.riskScore: + "$serde_json::private::Number": "30" + dueDiligenceLevel: standard + rule: + _id: add4 + "assessment.riskScore[i2]": "< 40" + "dueDiligenceLevel[i1]": "'standard'" + customerRiskScoring: + id: customerRiskScoring + input: + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + watchlist: + adverseMediaMatch: false + pepListMatch: false + sanctionsMatch: false + name: customerRiskScoring + order: + "$serde_json::private::Number": "1" + output: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + watchlist: + adverseMediaMatch: false + pepListMatch: false + sanctionsMatch: false + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + customer.address.country: US + customer.isHighRiskBusiness: false + customer.isPoliticallyExposed: false + financialInfo.estimatedTransactionValue: + "$serde_json::private::Number": "25000" + rule: + _id: risk2 + "customer.address.country[country]": "'US', 'CA', 'GB', 'AU', 'NZ', 'JP', 'DE', 'FR'" + "customer.isHighRiskBusiness[highRiskBusiness]": "false" + "customer.isPoliticallyExposed[pep]": "false" + "financialInfo.estimatedTransactionValue[transactionValue]": ">= 10000, < 100000" + documentVerification: + id: documentVerification + input: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + watchlist: + adverseMediaMatch: false + pepListMatch: false + sanctionsMatch: false + name: documentVerification + order: + "$serde_json::private::Number": "2" + output: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + documentVerificationStatus: standard + isDocumentVerified: true + requiresAdditionalVerification: false + watchlist: + adverseMediaMatch: false + pepListMatch: false + sanctionsMatch: false + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + assessment.riskLevel: medium + verification.documentStatus: valid + verification.documentType: passport + rule: + _id: doc1 + "assessment.riskLevel[i3]": "'low', 'medium'" + "verification.documentStatus[i2]": "'valid'" + "verification.documentType[i1]": "'passport'" + dueDiligenceLevel: + id: dueDiligenceLevel + input: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + documentVerificationStatus: standard + isDocumentVerified: true + requiresAdditionalVerification: false + watchlist: + adverseMediaMatch: false + message: No watchlist hits found + passed: true + pepListMatch: false + sanctionsMatch: false + status: pass + name: dueDiligenceLevel + order: + "$serde_json::private::Number": "4" + output: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + dueDiligenceLevel: standard + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + isSanctioned: false + requiresEDD: false + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + documentVerificationStatus: standard + isDocumentVerified: true + requiresAdditionalVerification: false + watchlist: + adverseMediaMatch: false + message: No watchlist hits found + passed: true + pepListMatch: false + sanctionsMatch: false + status: pass + performance: "[perf]" + traceData: + dueDiligenceLevel: + result: "\"standard\"" + isSanctioned: + result: "false" + requiresEDD: + result: "false" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + watchlist: + adverseMediaMatch: false + pepListMatch: false + sanctionsMatch: false + performance: "[perf]" + traceData: ~ + verificationResult: + id: verificationResult + input: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + dueDiligenceLevel: standard + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + isSanctioned: false + requirements: + addressVerification: false + enhancedMonitoring: false + faceVerification: false + sourceOfFunds: false + requiresEDD: false + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + documentVerificationStatus: standard + isDocumentVerified: true + requiresAdditionalVerification: false + watchlist: + adverseMediaMatch: false + message: No watchlist hits found + passed: true + pepListMatch: false + sanctionsMatch: false + status: pass + name: verificationResult + order: + "$serde_json::private::Number": "6" + output: + nextSteps: Onboarding approved + requiredActionsCount: + "$serde_json::private::Number": "0" + requirements: + addressVerification: false + enhancedMonitoring: false + faceVerification: false + sourceOfFunds: false + verificationStatus: approved + performance: "[perf]" + traceData: + nextSteps: + result: "\"Onboarding approved\"" + requiredActionsCount: + result: "0" + requirements: + result: "{\"sourceOfFunds\":false,\"enhancedMonitoring\":false,\"faceVerification\":false,\"addressVerification\":false}" + verificationStatus: + result: "\"approved\"" + watchlistCheck: + id: watchlistCheck + input: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + documentVerificationStatus: standard + isDocumentVerified: true + requiresAdditionalVerification: false + watchlist: + adverseMediaMatch: false + pepListMatch: false + sanctionsMatch: false + name: watchlistCheck + order: + "$serde_json::private::Number": "3" + output: + assessment: + riskLevel: medium + riskScore: + "$serde_json::private::Number": "30" + customer: + address: + city: New York + country: US + line1: 123 Main Street + line2: Apt 4B + postalCode: "10001" + state: NY + dateOfBirth: 1985-06-15 + email: john.smith@example.com + employerName: Tech Company Inc. + firstName: John + id: CUST12345 + isHighRiskBusiness: false + isPoliticallyExposed: false + lastName: Smith + occupation: Software Engineer + phone: +1-555-123-4567 + financialInfo: + accountPurpose: Savings and Investment + estimatedTransactionValue: + "$serde_json::private::Number": "25000" + sourceOfFunds: Employment Income + verification: + documentExpiry: 2028-05-20 + documentIssuingCountry: US + documentNumber: P123456789 + documentStatus: valid + documentType: passport + documentVerificationStatus: standard + isDocumentVerified: true + requiresAdditionalVerification: false + watchlist: + adverseMediaMatch: false + message: No watchlist hits found + passed: true + pepListMatch: false + sanctionsMatch: false + status: pass + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + watchlist.adverseMediaMatch: false + watchlist.pepListMatch: false + watchlist.sanctionsMatch: false + rule: + _id: watch4 + "watchlist.adverseMediaMatch[i3]": "false" + "watchlist.pepListMatch[i2]": "false" + "watchlist.sanctionsMatch[i1]": "false" diff --git a/core/engine/tests/snapshots/engine__customer-service-escalation_0.snap b/core/engine/tests/snapshots/engine__customer-service-escalation_0.snap new file mode 100644 index 00000000..c1e8c8cb --- /dev/null +++ b/core/engine/tests/snapshots/engine__customer-service-escalation_0.snap @@ -0,0 +1,79 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + escalation: + assignedTeam: Executive Response Team + description: Immediate executive team escalation required + level: immediate_executive + priority: + "$serde_json::private::Number": "1" + slaMinutes: + "$serde_json::private::Number": "30" +trace: + dt1: + id: dt1 + input: + customer: + accountAge: + "$serde_json::private::Number": "36" + id: C123456 + name: Acme Corporation + tier: premium + issue: + complexity: high + description: Complete service outage affecting all production systems + financialImpact: + "$serde_json::private::Number": "7500" + id: ISS-789 + type: service_outage + name: determine_escalation_level + order: + "$serde_json::private::Number": "1" + output: + escalation: + assignedTeam: Executive Response Team + description: Immediate executive team escalation required + level: immediate_executive + priority: + "$serde_json::private::Number": "1" + slaMinutes: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + customer.tier: premium + issue.complexity: high + issue.financialImpact: + "$serde_json::private::Number": "7500" + rule: + _id: r1-1 + "customer.tier[i1-1]": "'premium'" + "issue.complexity[i1-2]": "'high'" + "issue.financialImpact[i1-3]": "> 5000" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + accountAge: + "$serde_json::private::Number": "36" + id: C123456 + name: Acme Corporation + tier: premium + issue: + complexity: high + description: Complete service outage affecting all production systems + financialImpact: + "$serde_json::private::Number": "7500" + id: ISS-789 + type: service_outage + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-discounts_0.snap b/core/engine/tests/snapshots/engine__decision-table-discounts_0.snap new file mode 100644 index 00000000..f6dad30a --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-discounts_0.snap @@ -0,0 +1,72 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + - discount: + percentage: + "$serde_json::private::Number": "15" +trace: + 5eefa8a4-56a9-46b1-a265-7ddbddde3441: + id: 5eefa8a4-56a9-46b1-a265-7ddbddde3441 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + code: WELCOME_2023 + customer: + joinDate: 2023-02-01 + pastPurchases: [] + order: + createdAt: 2023-01-15 + performance: "[perf]" + traceData: ~ + 638d767d-ae08-4ba3-9db3-97c6c4e4c6f5: + id: 638d767d-ae08-4ba3-9db3-97c6c4e4c6f5 + input: + code: WELCOME_2023 + customer: + joinDate: 2023-02-01 + pastPurchases: [] + order: + createdAt: 2023-01-15 + name: Discounts + order: + "$serde_json::private::Number": "1" + output: + - discount: + percentage: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: + code: WELCOME_2023 + date(customer.joinDate): + "$serde_json::private::Number": "1675209600" + date(order.createdAt): + "$serde_json::private::Number": "1673740800" + len(customer.pastPurchases): + "$serde_json::private::Number": "0" + rule: + _description: Welcome bonus of 15% + _id: eabd4e2e-5c14-4d4d-ada6-b3cdc547ae99 + "code[6fd35e3e-584b-4149-b4bf-5f2d258f40e7]": "\"WELCOME_2023\"" + "date(customer.joinDate)[813dace4-0b55-4409-adb2-b4739a653302]": "> date(\"2023-01-01\")" + "date(order.createdAt)[a1700de6-fe35-4cec-b66f-0897d2604a3f]": "" + "len(customer.pastPurchases)[f34f2c8b-eba9-4ebe-aeec-384bce69e3aa]": "0" + c87d26e6-f3a2-47ad-9310-cbd1899cc68a: + id: c87d26e6-f3a2-47ad-9310-cbd1899cc68a + input: + - discount: + percentage: + "$serde_json::private::Number": "15" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-discounts_1.snap b/core/engine/tests/snapshots/engine__decision-table-discounts_1.snap new file mode 100644 index 00000000..76509cb0 --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-discounts_1.snap @@ -0,0 +1,94 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + - discount: + flat: + "$serde_json::private::Number": "25" +trace: + 5eefa8a4-56a9-46b1-a265-7ddbddde3441: + id: 5eefa8a4-56a9-46b1-a265-7ddbddde3441 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + code: BACK_TO_BACK + customer: + joinDate: 2023-01-10 + pastPurchases: + - {} + - {} + - {} + - {} + - {} + - {} + - {} + - {} + - {} + - {} + - {} + order: + createdAt: 2023-01-20 + performance: "[perf]" + traceData: ~ + 638d767d-ae08-4ba3-9db3-97c6c4e4c6f5: + id: 638d767d-ae08-4ba3-9db3-97c6c4e4c6f5 + input: + code: BACK_TO_BACK + customer: + joinDate: 2023-01-10 + pastPurchases: + - {} + - {} + - {} + - {} + - {} + - {} + - {} + - {} + - {} + - {} + - {} + order: + createdAt: 2023-01-20 + name: Discounts + order: + "$serde_json::private::Number": "1" + output: + - discount: + flat: + "$serde_json::private::Number": "25" + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "1" + reference_map: + code: BACK_TO_BACK + date(customer.joinDate): + "$serde_json::private::Number": "1673308800" + date(order.createdAt): + "$serde_json::private::Number": "1674172800" + len(customer.pastPurchases): + "$serde_json::private::Number": "11" + rule: + _description: Recurring customer 25$ discount + _id: d80dee00-07a7-42fb-bc83-262eeee9fbdb + "code[6fd35e3e-584b-4149-b4bf-5f2d258f40e7]": "\"BACK_TO_BACK\"" + "date(customer.joinDate)[813dace4-0b55-4409-adb2-b4739a653302]": "" + "date(order.createdAt)[a1700de6-fe35-4cec-b66f-0897d2604a3f]": "[date(\"2023-01-01\")..date(\"2023-02-01\")]" + "len(customer.pastPurchases)[f34f2c8b-eba9-4ebe-aeec-384bce69e3aa]": "> 10" + c87d26e6-f3a2-47ad-9310-cbd1899cc68a: + id: c87d26e6-f3a2-47ad-9310-cbd1899cc68a + input: + - discount: + flat: + "$serde_json::private::Number": "25" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-discounts_2.snap b/core/engine/tests/snapshots/engine__decision-table-discounts_2.snap new file mode 100644 index 00000000..5f42f37b --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-discounts_2.snap @@ -0,0 +1,72 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + - discount: + percentage: + "$serde_json::private::Number": "10" +trace: + 5eefa8a4-56a9-46b1-a265-7ddbddde3441: + id: 5eefa8a4-56a9-46b1-a265-7ddbddde3441 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + code: EARLY_BIRD + customer: + joinDate: 2019-12-01 + pastPurchases: [] + order: + createdAt: 2022-01-15 + performance: "[perf]" + traceData: ~ + 638d767d-ae08-4ba3-9db3-97c6c4e4c6f5: + id: 638d767d-ae08-4ba3-9db3-97c6c4e4c6f5 + input: + code: EARLY_BIRD + customer: + joinDate: 2019-12-01 + pastPurchases: [] + order: + createdAt: 2022-01-15 + name: Discounts + order: + "$serde_json::private::Number": "1" + output: + - discount: + percentage: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "2" + reference_map: + code: EARLY_BIRD + date(customer.joinDate): + "$serde_json::private::Number": "1575158400" + date(order.createdAt): + "$serde_json::private::Number": "1642204800" + len(customer.pastPurchases): + "$serde_json::private::Number": "0" + rule: + _description: Old customer 10% + _id: fcfae4b3-5c86-4efe-91cd-ca4bc1fa7c7c + "code[6fd35e3e-584b-4149-b4bf-5f2d258f40e7]": "\"EARLY_BIRD\"" + "date(customer.joinDate)[813dace4-0b55-4409-adb2-b4739a653302]": "< date(\"2020-01-01\")" + "date(order.createdAt)[a1700de6-fe35-4cec-b66f-0897d2604a3f]": "" + "len(customer.pastPurchases)[f34f2c8b-eba9-4ebe-aeec-384bce69e3aa]": "" + c87d26e6-f3a2-47ad-9310-cbd1899cc68a: + id: c87d26e6-f3a2-47ad-9310-cbd1899cc68a + input: + - discount: + percentage: + "$serde_json::private::Number": "10" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_0.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_0.snap new file mode 100644 index 00000000..70ce0787 --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_0.snap @@ -0,0 +1,84 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: PREMIUM_HIGH + price: + "$serde_json::private::Number": "15" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: PREMIUM_HIGH + price: + "$serde_json::private::Number": "15" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "500" + - quantity: + "$serde_json::private::Number": "3" + unitPrice: + "$serde_json::private::Number": "300" + customer: + country: US + tags: + - premium + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: PREMIUM_HIGH + price: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + customer.country: US + customer.tags: + - premium + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "1900" + rule: + _id: ab7bcf2b-4594-4347-a085-5dac0601d7e5 + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "contains($, \"premium\")" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": ">= 1_000" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "500" + - quantity: + "$serde_json::private::Number": "3" + unitPrice: + "$serde_json::private::Number": "300" + customer: + country: US + tags: + - premium + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_1.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_1.snap new file mode 100644 index 00000000..0c6a87df --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_1.snap @@ -0,0 +1,84 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: PREMIUM_MEDIUM + price: + "$serde_json::private::Number": "20" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: PREMIUM_MEDIUM + price: + "$serde_json::private::Number": "20" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "300" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "100" + customer: + country: US + tags: + - premium + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: PREMIUM_MEDIUM + price: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + customer.country: US + customer.tags: + - premium + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "500" + rule: + _id: 4a2ae2e9-9ad7-45b2-9fad-db26e3cab0c8 + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "contains($, \"premium\")" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": "[500..1_000)" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "300" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "100" + customer: + country: US + tags: + - premium + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_10.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_10.snap new file mode 100644 index 00000000..b32484d4 --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_10.snap @@ -0,0 +1,81 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: ROW_MEDIUM + price: + "$serde_json::private::Number": "45" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: ROW_MEDIUM + price: + "$serde_json::private::Number": "45" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "400" + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "199.99" + customer: + country: ROW + tags: [] + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: ROW_MEDIUM + price: + "$serde_json::private::Number": "45" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "10" + reference_map: + customer.country: ROW + customer.tags: [] + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "999.99" + rule: + _id: 3c32d0b0-32a1-465c-9f50-643f8f2a0700 + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": "[500..1_000)" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "400" + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "199.99" + customer: + country: ROW + tags: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_11.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_11.snap new file mode 100644 index 00000000..290600a8 --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_11.snap @@ -0,0 +1,73 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: ROW_LOW + price: + "$serde_json::private::Number": "50" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: ROW_LOW + price: + "$serde_json::private::Number": "50" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "499.99" + customer: + country: ROW + tags: [] + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: ROW_LOW + price: + "$serde_json::private::Number": "50" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "11" + reference_map: + customer.country: ROW + customer.tags: [] + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "499.99" + rule: + _id: 5449fa1d-78f1-463f-a4e7-6ce8018adf1f + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": "" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "499.99" + customer: + country: ROW + tags: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_2.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_2.snap new file mode 100644 index 00000000..85bf65e4 --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_2.snap @@ -0,0 +1,84 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: PREMIUM_LOW + price: + "$serde_json::private::Number": "25" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: PREMIUM_LOW + price: + "$serde_json::private::Number": "25" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "300" + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "100" + customer: + country: US + tags: + - premium + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: PREMIUM_LOW + price: + "$serde_json::private::Number": "25" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + customer.country: US + customer.tags: + - premium + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "400" + rule: + _id: b7aaeca2-7e42-4fb2-9867-eb4e43ca911d + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "contains($, \"premium\")" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": "" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "300" + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "100" + customer: + country: US + tags: + - premium + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_3.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_3.snap new file mode 100644 index 00000000..0044b0ea --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_3.snap @@ -0,0 +1,81 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: US_HIGH + price: + "$serde_json::private::Number": "25" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: US_HIGH + price: + "$serde_json::private::Number": "25" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "1500" + - quantity: + "$serde_json::private::Number": "3" + unitPrice: + "$serde_json::private::Number": "800" + customer: + country: US + tags: [] + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: US_HIGH + price: + "$serde_json::private::Number": "25" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + customer.country: US + customer.tags: [] + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "5400" + rule: + _id: a179f314-512c-4cc6-a892-5f1e0b6b979c + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "\"US\"" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": ">= 1_000" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "1500" + - quantity: + "$serde_json::private::Number": "3" + unitPrice: + "$serde_json::private::Number": "800" + customer: + country: US + tags: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_4.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_4.snap new file mode 100644 index 00000000..f961d22f --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_4.snap @@ -0,0 +1,81 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: US_MEDIUM + price: + "$serde_json::private::Number": "35" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: US_MEDIUM + price: + "$serde_json::private::Number": "35" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "300" + - quantity: + "$serde_json::private::Number": "3" + unitPrice: + "$serde_json::private::Number": "50" + customer: + country: US + tags: [] + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: US_MEDIUM + price: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + customer.country: US + customer.tags: [] + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "750" + rule: + _id: db1f0c0e-e48a-4f9f-95fe-04e143cfd029 + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "\"US\"" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": "[500..1_000)" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "300" + - quantity: + "$serde_json::private::Number": "3" + unitPrice: + "$serde_json::private::Number": "50" + customer: + country: US + tags: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_5.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_5.snap new file mode 100644 index 00000000..2a2100ac --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_5.snap @@ -0,0 +1,81 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: US_LOW + price: + "$serde_json::private::Number": "40" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: US_LOW + price: + "$serde_json::private::Number": "40" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "200" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "125" + customer: + country: US + tags: [] + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: US_LOW + price: + "$serde_json::private::Number": "40" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "5" + reference_map: + customer.country: US + customer.tags: [] + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "450" + rule: + _id: 3110b1b5-6552-48c4-8a78-417ee6185125 + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "\"US\"" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": "" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "200" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "125" + customer: + country: US + tags: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_6.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_6.snap new file mode 100644 index 00000000..b441fe12 --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_6.snap @@ -0,0 +1,81 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: UK_HIGH + price: + "$serde_json::private::Number": "20" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: UK_HIGH + price: + "$serde_json::private::Number": "20" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "700" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "900" + customer: + country: IE + tags: [] + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: UK_HIGH + price: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "6" + reference_map: + customer.country: IE + customer.tags: [] + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "2500" + rule: + _id: 6ad80268-5400-45f4-977f-07515cc0d4a0 + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "\"GB\", \"IE\"" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": ">= 1_000" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "700" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "900" + customer: + country: IE + tags: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_7.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_7.snap new file mode 100644 index 00000000..4c757ab3 --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_7.snap @@ -0,0 +1,81 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: UK_MEDIUM + price: + "$serde_json::private::Number": "30" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: UK_MEDIUM + price: + "$serde_json::private::Number": "30" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "400" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "200" + customer: + country: GB + tags: [] + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: UK_MEDIUM + price: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "7" + reference_map: + customer.country: GB + customer.tags: [] + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "800" + rule: + _id: b814770e-c35b-406b-ba0a-39e2832853bc + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "\"GB\", \"IE\"" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": "[500..1_000)" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "400" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "200" + customer: + country: GB + tags: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_8.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_8.snap new file mode 100644 index 00000000..ea7c36c1 --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_8.snap @@ -0,0 +1,81 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: UK_LOW + price: + "$serde_json::private::Number": "35" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: UK_LOW + price: + "$serde_json::private::Number": "35" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "200" + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "100" + customer: + country: IE + tags: [] + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: UK_LOW + price: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "8" + reference_map: + customer.country: IE + customer.tags: [] + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "300" + rule: + _id: 705783d4-e015-47d6-98fc-84f6544b3ce1 + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "\"GB\", \"IE\"" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": "" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "200" + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "100" + customer: + country: IE + tags: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__decision-table-shipping_9.snap b/core/engine/tests/snapshots/engine__decision-table-shipping_9.snap new file mode 100644 index 00000000..7600c772 --- /dev/null +++ b/core/engine/tests/snapshots/engine__decision-table-shipping_9.snap @@ -0,0 +1,81 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + group: ROW_HIGH + price: + "$serde_json::private::Number": "35" +trace: + 2938f93f-1dce-4f85-a401-44c224d9237f: + id: 2938f93f-1dce-4f85-a401-44c224d9237f + input: + group: ROW_HIGH + price: + "$serde_json::private::Number": "35" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ + 405841da-b7bb-4f4e-824f-21f1f4bc6fd9: + id: 405841da-b7bb-4f4e-824f-21f1f4bc6fd9 + input: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "1500" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "1200" + customer: + country: ROW + tags: [] + name: Shipping Fees + order: + "$serde_json::private::Number": "1" + output: + group: ROW_HIGH + price: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "9" + reference_map: + customer.country: ROW + customer.tags: [] + "sum(map(cart.items, #.unitPrice * #.quantity))": + "$serde_json::private::Number": "3900" + rule: + _id: 889c2ab2-d495-4299-9809-3aac70352c9b + "customer.country[d89ca9da-581e-4392-a990-24cde9c33a2b]": "" + "customer.tags[184cc5f5-f459-41cf-814b-79f6ffea695d]": "" + "sum(map(cart.items, #.unitPrice * #.quantity))[ea23eec9-76c5-4b62-821c-aec504545506]": ">= 1_000" + 4c688656-05ba-4503-a582-02e6e4a5a135: + id: 4c688656-05ba-4503-a582-02e6e4a5a135 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + cart: + items: + - quantity: + "$serde_json::private::Number": "1" + unitPrice: + "$serde_json::private::Number": "1500" + - quantity: + "$serde_json::private::Number": "2" + unitPrice: + "$serde_json::private::Number": "1200" + customer: + country: ROW + tags: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__delivery-route-optimizer_0.snap b/core/engine/tests/snapshots/engine__delivery-route-optimizer_0.snap new file mode 100644 index 00000000..b5b27586 --- /dev/null +++ b/core/engine/tests/snapshots/engine__delivery-route-optimizer_0.snap @@ -0,0 +1,222 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + distanceScore: + "$serde_json::private::Number": "30" + route: + capacityUtilization: + "$serde_json::private::Number": "0.85" + deliveryWindowMinutes: + "$serde_json::private::Number": "45" + distanceKm: + "$serde_json::private::Number": "8.5" + id: R1234 + name: Downtown Loop + otherCondition: normal + trafficCongestionMinutes: + "$serde_json::private::Number": "12" + routeResult: + classification: recommended + isApproved: true + message: Route is recommended with good score. + routeScores: + baseScore: + "$serde_json::private::Number": "100" + priority: high + timeWindowScore: + "$serde_json::private::Number": "30" + totalScore: + "$serde_json::private::Number": "160" +trace: + dt1: + id: dt1 + input: + route: + capacityUtilization: + "$serde_json::private::Number": "0.85" + deliveryWindowMinutes: + "$serde_json::private::Number": "45" + distanceKm: + "$serde_json::private::Number": "8.5" + id: R1234 + name: Downtown Loop + otherCondition: normal + trafficCongestionMinutes: + "$serde_json::private::Number": "12" + name: evaluate_base_score + order: + "$serde_json::private::Number": "1" + output: + route: + capacityUtilization: + "$serde_json::private::Number": "0.85" + deliveryWindowMinutes: + "$serde_json::private::Number": "45" + distanceKm: + "$serde_json::private::Number": "8.5" + id: R1234 + name: Downtown Loop + otherCondition: normal + trafficCongestionMinutes: + "$serde_json::private::Number": "12" + routeScores: + baseScore: + "$serde_json::private::Number": "100" + priority: high + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + route.capacityUtilization: + "$serde_json::private::Number": "0.85" + route.otherCondition: normal + route.trafficCongestionMinutes: + "$serde_json::private::Number": "12" + rule: + _id: r1-1 + "route.capacityUtilization[i1-1]": "> 0.8" + "route.otherCondition[i1-3]": "" + "route.trafficCongestionMinutes[i1-2]": "< 15" + dt2: + id: dt2 + input: + distanceScore: + "$serde_json::private::Number": "30" + route: + capacityUtilization: + "$serde_json::private::Number": "0.85" + deliveryWindowMinutes: + "$serde_json::private::Number": "45" + distanceKm: + "$serde_json::private::Number": "8.5" + id: R1234 + name: Downtown Loop + otherCondition: normal + trafficCongestionMinutes: + "$serde_json::private::Number": "12" + routeScores: + baseScore: + "$serde_json::private::Number": "100" + priority: high + timeWindowScore: + "$serde_json::private::Number": "30" + totalScore: + "$serde_json::private::Number": "160" + name: determine_route_approval + order: + "$serde_json::private::Number": "3" + output: + distanceScore: + "$serde_json::private::Number": "30" + route: + capacityUtilization: + "$serde_json::private::Number": "0.85" + deliveryWindowMinutes: + "$serde_json::private::Number": "45" + distanceKm: + "$serde_json::private::Number": "8.5" + id: R1234 + name: Downtown Loop + otherCondition: normal + trafficCongestionMinutes: + "$serde_json::private::Number": "12" + routeResult: + classification: recommended + isApproved: true + message: Route is recommended with good score. + routeScores: + baseScore: + "$serde_json::private::Number": "100" + priority: high + timeWindowScore: + "$serde_json::private::Number": "30" + totalScore: + "$serde_json::private::Number": "160" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + totalScore: + "$serde_json::private::Number": "160" + rule: + _id: r2-2 + "totalScore[i2-1]": "> 120" + ex1: + id: ex1 + input: + route: + capacityUtilization: + "$serde_json::private::Number": "0.85" + deliveryWindowMinutes: + "$serde_json::private::Number": "45" + distanceKm: + "$serde_json::private::Number": "8.5" + id: R1234 + name: Downtown Loop + otherCondition: normal + trafficCongestionMinutes: + "$serde_json::private::Number": "12" + routeScores: + baseScore: + "$serde_json::private::Number": "100" + priority: high + name: calculate_additional_scores + order: + "$serde_json::private::Number": "2" + output: + distanceScore: + "$serde_json::private::Number": "30" + route: + capacityUtilization: + "$serde_json::private::Number": "0.85" + deliveryWindowMinutes: + "$serde_json::private::Number": "45" + distanceKm: + "$serde_json::private::Number": "8.5" + id: R1234 + name: Downtown Loop + otherCondition: normal + trafficCongestionMinutes: + "$serde_json::private::Number": "12" + routeScores: + baseScore: + "$serde_json::private::Number": "100" + priority: high + timeWindowScore: + "$serde_json::private::Number": "30" + totalScore: + "$serde_json::private::Number": "160" + performance: "[perf]" + traceData: + distanceScore: + result: "30" + timeWindowScore: + result: "30" + totalScore: + result: "160" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + route: + capacityUtilization: + "$serde_json::private::Number": "0.85" + deliveryWindowMinutes: + "$serde_json::private::Number": "45" + distanceKm: + "$serde_json::private::Number": "8.5" + id: R1234 + name: Downtown Loop + otherCondition: normal + trafficCongestionMinutes: + "$serde_json::private::Number": "12" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__device-compatibility-checker_0.snap b/core/engine/tests/snapshots/engine__device-compatibility-checker_0.snap new file mode 100644 index 00000000..2fa1dbf3 --- /dev/null +++ b/core/engine/tests/snapshots/engine__device-compatibility-checker_0.snap @@ -0,0 +1,145 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + compatibility: + advancedFeatures: true + basicService: true + hdStreaming: false + nextGenFeatures: false + deviceFirmware: 14.2.1 + deviceId: A1B2C3D4E5F6 + deviceModel: iPhone 13 Pro + majorVersion: + "$serde_json::private::Number": "14" + normalizedModel: iphone 13 pro + requestTimestamp: "2023-04-15T10:30:45Z" + subscriberId: "2022050789" +trace: + dt1: + id: dt1 + input: + deviceFirmware: 14.2.1 + deviceId: A1B2C3D4E5F6 + deviceModel: iPhone 13 Pro + majorVersion: + "$serde_json::private::Number": "14" + normalizedModel: iphone 13 pro + requestTimestamp: "2023-04-15T10:30:45Z" + subscriberId: "2022050789" + name: determine_compatibility + order: + "$serde_json::private::Number": "2" + output: + compatibility: + advancedFeatures: true + basicService: true + hdStreaming: true + nextGenFeatures: false + deviceFirmware: 14.2.1 + deviceId: A1B2C3D4E5F6 + deviceModel: iPhone 13 Pro + majorVersion: + "$serde_json::private::Number": "14" + normalizedModel: iphone 13 pro + requestTimestamp: "2023-04-15T10:30:45Z" + subscriberId: "2022050789" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + majorVersion: + "$serde_json::private::Number": "14" + normalizedModel: iphone 13 pro + rule: + _id: r1-2 + "majorVersion[i1-2]": ">= 13 and < 15" + "normalizedModel[i1-1]": "contains($, 'iphone')" + dt2: + id: dt2 + input: + compatibility: + advancedFeatures: true + basicService: true + hdStreaming: true + nextGenFeatures: false + deviceFirmware: 14.2.1 + deviceId: A1B2C3D4E5F6 + deviceModel: iPhone 13 Pro + majorVersion: + "$serde_json::private::Number": "14" + normalizedModel: iphone 13 pro + requestTimestamp: "2023-04-15T10:30:45Z" + subscriberId: "2022050789" + name: check_minor_version + order: + "$serde_json::private::Number": "3" + output: + compatibility: + advancedFeatures: true + basicService: true + hdStreaming: false + nextGenFeatures: false + deviceFirmware: 14.2.1 + deviceId: A1B2C3D4E5F6 + deviceModel: iPhone 13 Pro + majorVersion: + "$serde_json::private::Number": "14" + normalizedModel: iphone 13 pro + requestTimestamp: "2023-04-15T10:30:45Z" + subscriberId: "2022050789" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + majorVersion: + "$serde_json::private::Number": "14" + normalizedModel: iphone 13 pro + rule: + _id: r2-1 + "majorVersion[624d983d-f416-4f68-b194-750f45445670]": "<= 14" + "normalizedModel[i2-1]": "contains($, 'iphone')" + ex1: + id: ex1 + input: + deviceFirmware: 14.2.1 + deviceId: A1B2C3D4E5F6 + deviceModel: iPhone 13 Pro + requestTimestamp: "2023-04-15T10:30:45Z" + subscriberId: "2022050789" + name: normalize_data + order: + "$serde_json::private::Number": "1" + output: + deviceFirmware: 14.2.1 + deviceId: A1B2C3D4E5F6 + deviceModel: iPhone 13 Pro + majorVersion: + "$serde_json::private::Number": "14" + normalizedModel: iphone 13 pro + requestTimestamp: "2023-04-15T10:30:45Z" + subscriberId: "2022050789" + performance: "[perf]" + traceData: + majorVersion: + result: "14" + normalizedModel: + result: "\"iphone 13 pro\"" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + deviceFirmware: 14.2.1 + deviceId: A1B2C3D4E5F6 + deviceModel: iPhone 13 Pro + requestTimestamp: "2023-04-15T10:30:45Z" + subscriberId: "2022050789" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__disaster-relief-fund-allocation_0.snap b/core/engine/tests/snapshots/engine__disaster-relief-fund-allocation_0.snap new file mode 100644 index 00000000..cfac0c44 --- /dev/null +++ b/core/engine/tests/snapshots/engine__disaster-relief-fund-allocation_0.snap @@ -0,0 +1,335 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + householdMultiplier: + "$serde_json::private::Number": "1.6" + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + initialAllocation: + "$serde_json::private::Number": "14400" + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + relief: + baseAmount: + "$serde_json::private::Number": "7500" + incomeAdjustedAmount: + "$serde_json::private::Number": "9000" + paymentAmount: + "$serde_json::private::Number": "10080" + paymentReason: Partially insured - reduced payment +trace: + dt1: + id: dt1 + input: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + name: baseFundAllocation + order: + "$serde_json::private::Number": "1" + output: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + relief: + baseAmount: + "$serde_json::private::Number": "7500" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + assessment.damageLevel: major + rule: + _id: r1-2 + "assessment.damageLevel[i1-1]": "'major'" + dt2: + id: dt2 + input: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + householdMultiplier: + "$serde_json::private::Number": "1.6" + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + initialAllocation: + "$serde_json::private::Number": "14400" + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + relief: + baseAmount: + "$serde_json::private::Number": "7500" + incomeAdjustedAmount: + "$serde_json::private::Number": "9000" + name: insuranceAdjustment + order: + "$serde_json::private::Number": "4" + output: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + householdMultiplier: + "$serde_json::private::Number": "1.6" + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + initialAllocation: + "$serde_json::private::Number": "14400" + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + relief: + baseAmount: + "$serde_json::private::Number": "7500" + incomeAdjustedAmount: + "$serde_json::private::Number": "9000" + paymentAmount: + "$serde_json::private::Number": "10080" + paymentReason: Partially insured - reduced payment + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + insurance.status: partial + rule: + _id: r2-2 + "insurance.status[i2-1]": "'partial'" + dt3: + id: dt3 + input: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + relief: + baseAmount: + "$serde_json::private::Number": "7500" + name: incomeAdjustment + order: + "$serde_json::private::Number": "2" + output: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + relief: + baseAmount: + "$serde_json::private::Number": "7500" + incomeAdjustedAmount: + "$serde_json::private::Number": "9000" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + income.level: low + rule: + _id: r3-1 + "income.level[i3-1]": "'low'" + ex1: + id: ex1 + input: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + relief: + baseAmount: + "$serde_json::private::Number": "7500" + incomeAdjustedAmount: + "$serde_json::private::Number": "9000" + name: householdSizeAdjustment + order: + "$serde_json::private::Number": "3" + output: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + householdMultiplier: + "$serde_json::private::Number": "1.6" + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + initialAllocation: + "$serde_json::private::Number": "14400" + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + relief: + baseAmount: + "$serde_json::private::Number": "7500" + incomeAdjustedAmount: + "$serde_json::private::Number": "9000" + performance: "[perf]" + traceData: + householdMultiplier: + result: "1.6" + initialAllocation: + result: "14400" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + assessment: + damageDescription: "Roof collapsed in multiple areas, extensive water damage" + damageLevel: major + propertyType: residential + household: + dependents: + "$serde_json::private::Number": "2" + size: + "$serde_json::private::Number": "4" + specialNeeds: false + income: + annualAmount: + "$serde_json::private::Number": "32000" + level: low + primarySource: employment + insurance: + deductible: + "$serde_json::private::Number": "5000" + provider: StateInsurance + status: partial + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__dynamic-fx-rate-pricing-system_0.snap b/core/engine/tests/snapshots/engine__dynamic-fx-rate-pricing-system_0.snap new file mode 100644 index 00000000..e087a011 --- /dev/null +++ b/core/engine/tests/snapshots/engine__dynamic-fx-rate-pricing-system_0.snap @@ -0,0 +1,107 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + fxDetails: + discount: + "$serde_json::private::Number": "0.015" + message: Luxury products receive favorable rates + rate: + "$serde_json::private::Number": "0.91" +trace: + fxRateAdjustmentDT: + id: fxRateAdjustmentDT + input: + baseCurrency: USD + customerTier: gold + product: + basePrice: + "$serde_json::private::Number": "8500" + category: luxury + id: PRD-12345 + name: Luxury Watch + quantity: + "$serde_json::private::Number": "1" + targetCurrency: EUR + name: determineFXRateAdjustment + order: + "$serde_json::private::Number": "2" + output: + fxDetails: + discount: + "$serde_json::private::Number": "0.015" + message: Luxury products receive favorable rates + rate: + "$serde_json::private::Number": "0.91" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + baseCurrency: USD + product.category: luxury + targetCurrency: EUR + rule: + _id: rule3 + "baseCurrency[i2-2]": "'USD'" + "product.category[i2-1]": "'luxury'" + "targetCurrency[i2-3]": "'EUR'" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + baseCurrency: USD + customerTier: gold + product: + basePrice: + "$serde_json::private::Number": "8500" + id: PRD-12345 + name: Luxury Watch + quantity: + "$serde_json::private::Number": "1" + targetCurrency: EUR + performance: "[perf]" + traceData: ~ + productCategoryDT: + id: productCategoryDT + input: + baseCurrency: USD + customerTier: gold + product: + basePrice: + "$serde_json::private::Number": "8500" + id: PRD-12345 + name: Luxury Watch + quantity: + "$serde_json::private::Number": "1" + targetCurrency: EUR + name: determineProductCategory + order: + "$serde_json::private::Number": "1" + output: + baseCurrency: USD + customerTier: gold + product: + basePrice: + "$serde_json::private::Number": "8500" + category: luxury + id: PRD-12345 + name: Luxury Watch + quantity: + "$serde_json::private::Number": "1" + targetCurrency: EUR + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + product.basePrice: + "$serde_json::private::Number": "8500" + rule: + _id: rule2 + "product.basePrice[i1-1]": ">= 5000" diff --git a/core/engine/tests/snapshots/engine__dynamic-marketplace-comission-calculator_0.snap b/core/engine/tests/snapshots/engine__dynamic-marketplace-comission-calculator_0.snap new file mode 100644 index 00000000..5bc71e58 --- /dev/null +++ b/core/engine/tests/snapshots/engine__dynamic-marketplace-comission-calculator_0.snap @@ -0,0 +1,204 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + finalCommissionRate: + "$serde_json::private::Number": "0.168" + isPromotionActive: false + promotionAdjustment: + "$serde_json::private::Number": "0" + volumeMultiplier: + "$serde_json::private::Number": "1.2" +trace: + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + product: + category: electronics + id: prod-123 + promotion: + endDate: 2025-04-01 + startDate: 2025-02-01 + sales: + amount: + "$serde_json::private::Number": "750" + volume: + "$serde_json::private::Number": "120" + seller: + fulfillmentRate: + "$serde_json::private::Number": "97" + id: sell-456 + rating: + "$serde_json::private::Number": "4.7" + performance: "[perf]" + traceData: ~ + productCategory: + id: productCategory + input: + product: + category: electronics + id: prod-123 + promotion: + endDate: 2025-04-01 + startDate: 2025-02-01 + sales: + amount: + "$serde_json::private::Number": "750" + volume: + "$serde_json::private::Number": "120" + seller: + fulfillmentRate: + "$serde_json::private::Number": "97" + id: sell-456 + rating: + "$serde_json::private::Number": "4.7" + name: productCategoryRates + order: + "$serde_json::private::Number": "1" + output: + commission: + baseRate: + "$serde_json::private::Number": "0.12" + product: + category: electronics + id: prod-123 + promotion: + endDate: 2025-04-01 + startDate: 2025-02-01 + sales: + amount: + "$serde_json::private::Number": "750" + volume: + "$serde_json::private::Number": "120" + seller: + fulfillmentRate: + "$serde_json::private::Number": "97" + id: sell-456 + rating: + "$serde_json::private::Number": "4.7" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + product.category: electronics + sales.amount: + "$serde_json::private::Number": "750" + rule: + _id: r1 + "product.category[i1]": "'electronics'" + "sales.amount[i2]": "> 500" + promotionalPeriod: + id: promotionalPeriod + input: + commission: + baseRate: + "$serde_json::private::Number": "0.12" + performanceAdjustment: + "$serde_json::private::Number": "0.02" + product: + category: electronics + id: prod-123 + promotion: + endDate: 2025-04-01 + startDate: 2025-02-01 + sales: + amount: + "$serde_json::private::Number": "750" + volume: + "$serde_json::private::Number": "120" + seller: + fulfillmentRate: + "$serde_json::private::Number": "97" + id: sell-456 + rating: + "$serde_json::private::Number": "4.7" + name: promotionalAdjustment + order: + "$serde_json::private::Number": "3" + output: + finalCommissionRate: + "$serde_json::private::Number": "0.168" + isPromotionActive: false + promotionAdjustment: + "$serde_json::private::Number": "0" + volumeMultiplier: + "$serde_json::private::Number": "1.2" + performance: "[perf]" + traceData: + finalCommissionRate: + result: "0.168" + isPromotionActive: + result: "false" + promotionAdjustment: + result: "0" + volumeMultiplier: + result: "1.2" + sellerPerformance: + id: sellerPerformance + input: + commission: + baseRate: + "$serde_json::private::Number": "0.12" + product: + category: electronics + id: prod-123 + promotion: + endDate: 2025-04-01 + startDate: 2025-02-01 + sales: + amount: + "$serde_json::private::Number": "750" + volume: + "$serde_json::private::Number": "120" + seller: + fulfillmentRate: + "$serde_json::private::Number": "97" + id: sell-456 + rating: + "$serde_json::private::Number": "4.7" + name: sellerPerformanceAdjustment + order: + "$serde_json::private::Number": "2" + output: + commission: + baseRate: + "$serde_json::private::Number": "0.12" + performanceAdjustment: + "$serde_json::private::Number": "0.02" + product: + category: electronics + id: prod-123 + promotion: + endDate: 2025-04-01 + startDate: 2025-02-01 + sales: + amount: + "$serde_json::private::Number": "750" + volume: + "$serde_json::private::Number": "120" + seller: + fulfillmentRate: + "$serde_json::private::Number": "97" + id: sell-456 + rating: + "$serde_json::private::Number": "4.7" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + seller.fulfillmentRate: + "$serde_json::private::Number": "97" + seller.rating: + "$serde_json::private::Number": "4.7" + rule: + _id: r8 + "seller.fulfillmentRate[i4]": "> 95" + "seller.rating[i3]": "> 4.5" diff --git a/core/engine/tests/snapshots/engine__dynamic-shipping-cost-calculator_0.snap b/core/engine/tests/snapshots/engine__dynamic-shipping-cost-calculator_0.snap new file mode 100644 index 00000000..c0d4b10b --- /dev/null +++ b/core/engine/tests/snapshots/engine__dynamic-shipping-cost-calculator_0.snap @@ -0,0 +1,255 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + baseRate: + "$serde_json::private::Number": "30" + currentSeason: summer + customerTier: gold + dimensionalWeight: + "$serde_json::private::Number": "4.8" + distance: + "$serde_json::private::Number": "250" + distanceFactor: + "$serde_json::private::Number": "2.5" + effectiveWeight: + "$serde_json::private::Number": "25" + finalPrice: + "$serde_json::private::Number": "35.4375" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + tierDiscount: + "$serde_json::private::Number": "0.9" + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" +trace: + dt1: + id: dt1 + input: + customerTier: gold + distance: + "$serde_json::private::Number": "250" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" + name: base_rate_calculation + order: + "$serde_json::private::Number": "1" + output: + baseRate: + "$serde_json::private::Number": "30" + customerTier: gold + distance: + "$serde_json::private::Number": "250" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + shippingType: express + weight: + "$serde_json::private::Number": "25" + rule: + _id: r1-5 + "shippingType[i1-1]": "'express'" + "weight[i1-2]": "[20..50]" + dt2: + id: dt2 + input: + baseRate: + "$serde_json::private::Number": "30" + currentSeason: summer + customerTier: gold + dimensionalWeight: + "$serde_json::private::Number": "4.8" + distance: + "$serde_json::private::Number": "250" + distanceFactor: + "$serde_json::private::Number": "2.5" + effectiveWeight: + "$serde_json::private::Number": "25" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" + name: calculate_final_price + order: + "$serde_json::private::Number": "4" + output: + baseRate: + "$serde_json::private::Number": "30" + currentSeason: summer + customerTier: gold + dimensionalWeight: + "$serde_json::private::Number": "4.8" + distance: + "$serde_json::private::Number": "250" + distanceFactor: + "$serde_json::private::Number": "2.5" + effectiveWeight: + "$serde_json::private::Number": "25" + finalPrice: + "$serde_json::private::Number": "35.4375" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + tierDiscount: + "$serde_json::private::Number": "0.9" + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + currentSeason: summer + customerTier: gold + rule: + _id: r2-5 + "currentSeason[i2-2]": "'summer'" + "customerTier[i2-1]": "'gold'" + dt3: + id: dt3 + input: + customerTier: gold + distance: + "$serde_json::private::Number": "250" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" + name: determine_season + order: + "$serde_json::private::Number": "2" + output: + currentSeason: summer + customerTier: gold + distance: + "$serde_json::private::Number": "250" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + "dayOfYear('now')": + "$serde_json::private::Number": "232" + rule: + _id: r3-3 + "dayOfYear('now')[i3-1]": "> 172 and < 265" + ex1: + id: ex1 + input: + baseRate: + "$serde_json::private::Number": "30" + currentSeason: summer + customerTier: gold + distance: + "$serde_json::private::Number": "250" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" + name: calculate_factors + order: + "$serde_json::private::Number": "3" + output: + baseRate: + "$serde_json::private::Number": "30" + currentSeason: summer + customerTier: gold + dimensionalWeight: + "$serde_json::private::Number": "4.8" + distance: + "$serde_json::private::Number": "250" + distanceFactor: + "$serde_json::private::Number": "2.5" + effectiveWeight: + "$serde_json::private::Number": "25" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + dimensionalWeight: + result: "4.8" + distanceFactor: + result: "2.5" + effectiveWeight: + result: "25" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customerTier: gold + distance: + "$serde_json::private::Number": "250" + height: + "$serde_json::private::Number": "20" + length: + "$serde_json::private::Number": "40" + shippingType: express + weight: + "$serde_json::private::Number": "25" + width: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__dynamic-tarrif-engine_0.snap b/core/engine/tests/snapshots/engine__dynamic-tarrif-engine_0.snap new file mode 100644 index 00000000..6af60715 --- /dev/null +++ b/core/engine/tests/snapshots/engine__dynamic-tarrif-engine_0.snap @@ -0,0 +1,171 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + baseTariff: + "$serde_json::private::Number": "0.05" + currency: EUR + finalTariff: + "$serde_json::private::Number": "0.048" + rulesSummary: + - "Base rate: 0.05 per unit" + - Premium user call discount + - Peak hour domestic rate +trace: + calculateFinalTariff: + id: calculateFinalTariff + input: + currency: EUR + locationType: domestic + profileMultiplier: + "$serde_json::private::Number": "0.8" + profileRuleApplied: Premium user call discount + serviceType: calls + timeLocationMultiplier: + "$serde_json::private::Number": "1.2" + timeLocationRuleApplied: Peak hour domestic rate + timePeriod: peak + timestamp: "2025-03-20T14:30:00Z" + usage: + amount: + "$serde_json::private::Number": "15" + unit: minutes + userId: USR123456 + userProfile: premium + name: calculateFinalTariff + order: + "$serde_json::private::Number": "3" + output: + baseTariff: + "$serde_json::private::Number": "0.05" + currency: EUR + finalTariff: + "$serde_json::private::Number": "0.048" + rulesSummary: + - "Base rate: 0.05 per unit" + - Premium user call discount + - Peak hour domestic rate + performance: "[perf]" + traceData: + baseTariff: + result: "0.05" + currency: + result: "\"EUR\"" + finalTariff: + result: "0.048" + rulesSummary: + result: "[\"Base rate: 0.05 per unit\",\"Premium user call discount\",\"Peak hour domestic rate\"]" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + currency: EUR + locationType: domestic + serviceType: calls + timePeriod: peak + timestamp: "2025-03-20T14:30:00Z" + usage: + amount: + "$serde_json::private::Number": "15" + unit: minutes + userId: USR123456 + userProfile: premium + performance: "[perf]" + traceData: ~ + profileRules: + id: profileRules + input: + currency: EUR + locationType: domestic + serviceType: calls + timePeriod: peak + timestamp: "2025-03-20T14:30:00Z" + usage: + amount: + "$serde_json::private::Number": "15" + unit: minutes + userId: USR123456 + userProfile: premium + name: userProfileRules + order: + "$serde_json::private::Number": "1" + output: + currency: EUR + locationType: domestic + profileMultiplier: + "$serde_json::private::Number": "0.8" + profileRuleApplied: Premium user call discount + serviceType: calls + timePeriod: peak + timestamp: "2025-03-20T14:30:00Z" + usage: + amount: + "$serde_json::private::Number": "15" + unit: minutes + userId: USR123456 + userProfile: premium + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + serviceType: calls + userProfile: premium + rule: + _id: r1 + "serviceType[i2]": "'calls'" + "userProfile[i1]": "'premium'" + timeLocationRules: + id: timeLocationRules + input: + currency: EUR + locationType: domestic + profileMultiplier: + "$serde_json::private::Number": "0.8" + profileRuleApplied: Premium user call discount + serviceType: calls + timePeriod: peak + timestamp: "2025-03-20T14:30:00Z" + usage: + amount: + "$serde_json::private::Number": "15" + unit: minutes + userId: USR123456 + userProfile: premium + name: timeLocationRules + order: + "$serde_json::private::Number": "2" + output: + currency: EUR + locationType: domestic + profileMultiplier: + "$serde_json::private::Number": "0.8" + profileRuleApplied: Premium user call discount + serviceType: calls + timeLocationMultiplier: + "$serde_json::private::Number": "1.2" + timeLocationRuleApplied: Peak hour domestic rate + timePeriod: peak + timestamp: "2025-03-20T14:30:00Z" + usage: + amount: + "$serde_json::private::Number": "15" + unit: minutes + userId: USR123456 + userProfile: premium + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + locationType: domestic + timePeriod: peak + rule: + _id: r2 + "locationType[i2]": "'domestic'" + "timePeriod[i1]": "'peak'" diff --git a/core/engine/tests/snapshots/engine__dynamic-ticket-pricing_0.snap b/core/engine/tests/snapshots/engine__dynamic-ticket-pricing_0.snap new file mode 100644 index 00000000..6d1ed0e8 --- /dev/null +++ b/core/engine/tests/snapshots/engine__dynamic-ticket-pricing_0.snap @@ -0,0 +1,255 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + finalPrice: + "$serde_json::private::Number": "536.25" + priceStrategy: premium +trace: + dt1: + id: dt1 + input: + availableSeats: + "$serde_json::private::Number": "5" + avgCompetitorPrice: + "$serde_json::private::Number": "25" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "1" + demandForecast: + "$serde_json::private::Number": "95" + flightId: FL-123 + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + name: time_urgency + order: + "$serde_json::private::Number": "1" + output: + availableSeats: + "$serde_json::private::Number": "5" + avgCompetitorPrice: + "$serde_json::private::Number": "25" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "1" + demandForecast: + "$serde_json::private::Number": "95" + flightId: FL-123 + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + urgencyLevel: high + urgencyMultiplier: + "$serde_json::private::Number": "1.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + daysToDepature: + "$serde_json::private::Number": "1" + rule: + _id: r1-1 + "daysToDepature[i1-1]": "< 3" + dt2: + id: dt2 + input: + availabilityRatio: + "$serde_json::private::Number": "0.0277777777777777777777777778" + availableSeats: + "$serde_json::private::Number": "5" + avgCompetitorPrice: + "$serde_json::private::Number": "25" + basePrice: + "$serde_json::private::Number": "250" + competitiveIndex: + "$serde_json::private::Number": "0.1" + daysToDepature: + "$serde_json::private::Number": "1" + demandForecast: + "$serde_json::private::Number": "95" + demandIndex: + "$serde_json::private::Number": "0.95" + flightId: FL-123 + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + urgencyLevel: high + urgencyMultiplier: + "$serde_json::private::Number": "1.5" + name: inventory_demand + order: + "$serde_json::private::Number": "3" + output: + availabilityRatio: + "$serde_json::private::Number": "0.0277777777777777777777777778" + availableSeats: + "$serde_json::private::Number": "5" + avgCompetitorPrice: + "$serde_json::private::Number": "25" + basePrice: + "$serde_json::private::Number": "250" + competitiveIndex: + "$serde_json::private::Number": "0.1" + daysToDepature: + "$serde_json::private::Number": "1" + demandForecast: + "$serde_json::private::Number": "95" + demandIndex: + "$serde_json::private::Number": "0.95" + demandLevel: very_high + flightId: FL-123 + inventoryMultiplier: + "$serde_json::private::Number": "1.3" + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + urgencyLevel: high + urgencyMultiplier: + "$serde_json::private::Number": "1.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + availabilityRatio: + "$serde_json::private::Number": "0.0277777777777777777777777778" + demandIndex: + "$serde_json::private::Number": "0.95" + rule: + _id: r2-1 + "availabilityRatio[i2-1]": "< 0.2" + "demandIndex[i2-2]": "> 0.8" + dt3: + id: dt3 + input: + availabilityRatio: + "$serde_json::private::Number": "0.0277777777777777777777777778" + availableSeats: + "$serde_json::private::Number": "5" + avgCompetitorPrice: + "$serde_json::private::Number": "25" + basePrice: + "$serde_json::private::Number": "250" + competitiveIndex: + "$serde_json::private::Number": "0.1" + daysToDepature: + "$serde_json::private::Number": "1" + demandForecast: + "$serde_json::private::Number": "95" + demandIndex: + "$serde_json::private::Number": "0.95" + demandLevel: very_high + flightId: FL-123 + inventoryMultiplier: + "$serde_json::private::Number": "1.3" + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + urgencyLevel: high + urgencyMultiplier: + "$serde_json::private::Number": "1.5" + name: final_pricing + order: + "$serde_json::private::Number": "4" + output: + finalPrice: + "$serde_json::private::Number": "536.25" + priceStrategy: premium + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + competitiveIndex: + "$serde_json::private::Number": "0.1" + demandLevel: very_high + urgencyLevel: high + rule: + _id: r3-1 + "competitiveIndex[i3-3]": "< 0.9" + "demandLevel[i3-2]": "'very_high'" + "urgencyLevel[i3-1]": "'high'" + ex1: + id: ex1 + input: + availableSeats: + "$serde_json::private::Number": "5" + avgCompetitorPrice: + "$serde_json::private::Number": "25" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "1" + demandForecast: + "$serde_json::private::Number": "95" + flightId: FL-123 + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + urgencyLevel: high + urgencyMultiplier: + "$serde_json::private::Number": "1.5" + name: calculate_factors + order: + "$serde_json::private::Number": "2" + output: + availabilityRatio: + "$serde_json::private::Number": "0.0277777777777777777777777778" + availableSeats: + "$serde_json::private::Number": "5" + avgCompetitorPrice: + "$serde_json::private::Number": "25" + basePrice: + "$serde_json::private::Number": "250" + competitiveIndex: + "$serde_json::private::Number": "0.1" + daysToDepature: + "$serde_json::private::Number": "1" + demandForecast: + "$serde_json::private::Number": "95" + demandIndex: + "$serde_json::private::Number": "0.95" + flightId: FL-123 + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + urgencyLevel: high + urgencyMultiplier: + "$serde_json::private::Number": "1.5" + performance: "[perf]" + traceData: + availabilityRatio: + result: "0.0277777777777777777777777778" + competitiveIndex: + result: "0.1" + demandIndex: + result: "0.95" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + availableSeats: + "$serde_json::private::Number": "5" + avgCompetitorPrice: + "$serde_json::private::Number": "25" + basePrice: + "$serde_json::private::Number": "250" + daysToDepature: + "$serde_json::private::Number": "1" + demandForecast: + "$serde_json::private::Number": "95" + flightId: FL-123 + routeId: JFK-LAX + totalSeats: + "$serde_json::private::Number": "180" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__empty-column-with-space_0.snap b/core/engine/tests/snapshots/engine__empty-column-with-space_0.snap new file mode 100644 index 00000000..00bd625a --- /dev/null +++ b/core/engine/tests/snapshots/engine__empty-column-with-space_0.snap @@ -0,0 +1,51 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + output: true +trace: + 46fbad36-4bbe-44ac-833f-d30e0d37d8d7: + id: 46fbad36-4bbe-44ac-833f-d30e0d37d8d7 + input: + amount: + "$serde_json::private::Number": "10000000" + name: Amount Check + order: + "$serde_json::private::Number": "1" + output: + output: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + amount: + "$serde_json::private::Number": "10000000" + second: ~ + rule: + _id: fJxWqBVUNk + "amount[6xj5CMIFv9]": "> 1_000_000" + "second[07795ded-cb9b-4165-9b5e-783b066dda61]": " " + 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a: + id: 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + amount: + "$serde_json::private::Number": "10000000" + performance: "[perf]" + traceData: ~ + 95aa8f3c-f371-4e48-beb3-0b5775d2a814: + id: 95aa8f3c-f371-4e48-beb3-0b5775d2a814 + input: + output: true + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__empty-column-with-space_1.snap b/core/engine/tests/snapshots/engine__empty-column-with-space_1.snap new file mode 100644 index 00000000..110c38c2 --- /dev/null +++ b/core/engine/tests/snapshots/engine__empty-column-with-space_1.snap @@ -0,0 +1,51 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + output: false +trace: + 46fbad36-4bbe-44ac-833f-d30e0d37d8d7: + id: 46fbad36-4bbe-44ac-833f-d30e0d37d8d7 + input: + amount: + "$serde_json::private::Number": "10" + name: Amount Check + order: + "$serde_json::private::Number": "1" + output: + output: false + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + amount: + "$serde_json::private::Number": "10" + second: ~ + rule: + _id: SY7uwJEPqS + "amount[6xj5CMIFv9]": "" + "second[07795ded-cb9b-4165-9b5e-783b066dda61]": "" + 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a: + id: 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + amount: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: ~ + 95aa8f3c-f371-4e48-beb3-0b5775d2a814: + id: 95aa8f3c-f371-4e48-beb3-0b5775d2a814 + input: + output: false + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__empty-column-without-space_0.snap b/core/engine/tests/snapshots/engine__empty-column-without-space_0.snap new file mode 100644 index 00000000..c49cddc2 --- /dev/null +++ b/core/engine/tests/snapshots/engine__empty-column-without-space_0.snap @@ -0,0 +1,51 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + output: true +trace: + 46fbad36-4bbe-44ac-833f-d30e0d37d8d7: + id: 46fbad36-4bbe-44ac-833f-d30e0d37d8d7 + input: + amount: + "$serde_json::private::Number": "10000000" + name: Amount Check + order: + "$serde_json::private::Number": "1" + output: + output: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + amount: + "$serde_json::private::Number": "10000000" + second: ~ + rule: + _id: fJxWqBVUNk + "amount[6xj5CMIFv9]": "> 1_000_000" + "second[07795ded-cb9b-4165-9b5e-783b066dda61]": "" + 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a: + id: 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + amount: + "$serde_json::private::Number": "10000000" + performance: "[perf]" + traceData: ~ + 95aa8f3c-f371-4e48-beb3-0b5775d2a814: + id: 95aa8f3c-f371-4e48-beb3-0b5775d2a814 + input: + output: true + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__empty-column-without-space_1.snap b/core/engine/tests/snapshots/engine__empty-column-without-space_1.snap new file mode 100644 index 00000000..110c38c2 --- /dev/null +++ b/core/engine/tests/snapshots/engine__empty-column-without-space_1.snap @@ -0,0 +1,51 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + output: false +trace: + 46fbad36-4bbe-44ac-833f-d30e0d37d8d7: + id: 46fbad36-4bbe-44ac-833f-d30e0d37d8d7 + input: + amount: + "$serde_json::private::Number": "10" + name: Amount Check + order: + "$serde_json::private::Number": "1" + output: + output: false + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + amount: + "$serde_json::private::Number": "10" + second: ~ + rule: + _id: SY7uwJEPqS + "amount[6xj5CMIFv9]": "" + "second[07795ded-cb9b-4165-9b5e-783b066dda61]": "" + 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a: + id: 4e7e6bb9-f128-41e7-8cc5-b9d79670b96a + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + amount: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: ~ + 95aa8f3c-f371-4e48-beb3-0b5775d2a814: + id: 95aa8f3c-f371-4e48-beb3-0b5775d2a814 + input: + output: false + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__environment-compliance-assessment_0.snap b/core/engine/tests/snapshots/engine__environment-compliance-assessment_0.snap new file mode 100644 index 00000000..80f61181 --- /dev/null +++ b/core/engine/tests/snapshots/engine__environment-compliance-assessment_0.snap @@ -0,0 +1,438 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + assessment: + emissionThreshold: + "$serde_json::private::Number": "150" + industryRiskLevel: medium + audits: + lastAuditDate: 2025-01-15 + previousFindings: + "$serde_json::private::Number": "3" + resolvedFindings: + "$serde_json::private::Number": "2" + carbonIntensity: + "$serde_json::private::Number": "185" + compliance: + actionTimeframe: 60-days + recommendation: Medium-risk industry with significant threshold exceedance requires remediation plan within 60 days. + status: non-compliant + emissions: + carbonDioxideMetricTons: + "$serde_json::private::Number": "18500" + methaneMetricTons: + "$serde_json::private::Number": "120" + nitrousOxideMetricTons: + "$serde_json::private::Number": "45" + exceededThreshold: true + hasWasteViolations: true + hasWaterViolations: false + industry: manufacturing + location: + city: Detroit + country: United States + region: midwest + percentOverThreshold: + "$serde_json::private::Number": "23.33333333333333333333333333" + production: + units: million_units + volume: + "$serde_json::private::Number": "100" + waste: + hazardousWasteMetricTons: + "$serde_json::private::Number": "50" + nonHazardousWasteMetricTons: + "$serde_json::private::Number": "350" + recycledPercentage: + "$serde_json::private::Number": "22" + violations: + "$serde_json::private::Number": "1" + water: + consumptionKiloliters: + "$serde_json::private::Number": "250000" + treatedPercentage: + "$serde_json::private::Number": "85" + violations: + "$serde_json::private::Number": "0" +trace: + complianceStatus: + id: complianceStatus + input: + assessment: + emissionThreshold: + "$serde_json::private::Number": "150" + industryRiskLevel: medium + audits: + lastAuditDate: 2025-01-15 + previousFindings: + "$serde_json::private::Number": "3" + resolvedFindings: + "$serde_json::private::Number": "2" + carbonIntensity: + "$serde_json::private::Number": "185" + emissions: + carbonDioxideMetricTons: + "$serde_json::private::Number": "18500" + methaneMetricTons: + "$serde_json::private::Number": "120" + nitrousOxideMetricTons: + "$serde_json::private::Number": "45" + exceededThreshold: true + hasWasteViolations: true + hasWaterViolations: false + industry: manufacturing + location: + city: Detroit + country: United States + region: midwest + percentOverThreshold: + "$serde_json::private::Number": "23.33333333333333333333333333" + production: + units: million_units + volume: + "$serde_json::private::Number": "100" + waste: + hazardousWasteMetricTons: + "$serde_json::private::Number": "50" + nonHazardousWasteMetricTons: + "$serde_json::private::Number": "350" + recycledPercentage: + "$serde_json::private::Number": "22" + violations: + "$serde_json::private::Number": "1" + water: + consumptionKiloliters: + "$serde_json::private::Number": "250000" + treatedPercentage: + "$serde_json::private::Number": "85" + violations: + "$serde_json::private::Number": "0" + name: complianceStatus + order: + "$serde_json::private::Number": "3" + output: + assessment: + emissionThreshold: + "$serde_json::private::Number": "150" + industryRiskLevel: medium + audits: + lastAuditDate: 2025-01-15 + previousFindings: + "$serde_json::private::Number": "3" + resolvedFindings: + "$serde_json::private::Number": "2" + carbonIntensity: + "$serde_json::private::Number": "185" + compliance: + actionTimeframe: 60-days + recommendation: Medium-risk industry with significant threshold exceedance requires remediation plan within 60 days. + status: non-compliant + emissions: + carbonDioxideMetricTons: + "$serde_json::private::Number": "18500" + methaneMetricTons: + "$serde_json::private::Number": "120" + nitrousOxideMetricTons: + "$serde_json::private::Number": "45" + exceededThreshold: true + hasWasteViolations: true + hasWaterViolations: false + industry: manufacturing + location: + city: Detroit + country: United States + region: midwest + percentOverThreshold: + "$serde_json::private::Number": "23.33333333333333333333333333" + production: + units: million_units + volume: + "$serde_json::private::Number": "100" + waste: + hazardousWasteMetricTons: + "$serde_json::private::Number": "50" + nonHazardousWasteMetricTons: + "$serde_json::private::Number": "350" + recycledPercentage: + "$serde_json::private::Number": "22" + violations: + "$serde_json::private::Number": "1" + water: + consumptionKiloliters: + "$serde_json::private::Number": "250000" + treatedPercentage: + "$serde_json::private::Number": "85" + violations: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + assessment.industryRiskLevel: medium + exceededThreshold: true + percentOverThreshold: + "$serde_json::private::Number": "23.33333333333333333333333333" + rule: + _id: cs4 + "assessment.industryRiskLevel[i1]": "'medium', 'medium-low'" + "exceededThreshold[i2]": "true" + "percentOverThreshold[i3]": "> 20" + emissionsEvaluation: + id: emissionsEvaluation + input: + assessment: + emissionThreshold: + "$serde_json::private::Number": "150" + industryRiskLevel: medium + audits: + lastAuditDate: 2025-01-15 + previousFindings: + "$serde_json::private::Number": "3" + resolvedFindings: + "$serde_json::private::Number": "2" + emissions: + carbonDioxideMetricTons: + "$serde_json::private::Number": "18500" + methaneMetricTons: + "$serde_json::private::Number": "120" + nitrousOxideMetricTons: + "$serde_json::private::Number": "45" + industry: manufacturing + location: + city: Detroit + country: United States + region: midwest + production: + units: million_units + volume: + "$serde_json::private::Number": "100" + waste: + hazardousWasteMetricTons: + "$serde_json::private::Number": "50" + nonHazardousWasteMetricTons: + "$serde_json::private::Number": "350" + recycledPercentage: + "$serde_json::private::Number": "22" + violations: + "$serde_json::private::Number": "1" + water: + consumptionKiloliters: + "$serde_json::private::Number": "250000" + treatedPercentage: + "$serde_json::private::Number": "85" + violations: + "$serde_json::private::Number": "0" + name: emissionsEvaluation + order: + "$serde_json::private::Number": "2" + output: + assessment: + emissionThreshold: + "$serde_json::private::Number": "150" + industryRiskLevel: medium + audits: + lastAuditDate: 2025-01-15 + previousFindings: + "$serde_json::private::Number": "3" + resolvedFindings: + "$serde_json::private::Number": "2" + carbonIntensity: + "$serde_json::private::Number": "185" + emissions: + carbonDioxideMetricTons: + "$serde_json::private::Number": "18500" + methaneMetricTons: + "$serde_json::private::Number": "120" + nitrousOxideMetricTons: + "$serde_json::private::Number": "45" + exceededThreshold: true + hasWasteViolations: true + hasWaterViolations: false + industry: manufacturing + location: + city: Detroit + country: United States + region: midwest + percentOverThreshold: + "$serde_json::private::Number": "23.33333333333333333333333333" + production: + units: million_units + volume: + "$serde_json::private::Number": "100" + waste: + hazardousWasteMetricTons: + "$serde_json::private::Number": "50" + nonHazardousWasteMetricTons: + "$serde_json::private::Number": "350" + recycledPercentage: + "$serde_json::private::Number": "22" + violations: + "$serde_json::private::Number": "1" + water: + consumptionKiloliters: + "$serde_json::private::Number": "250000" + treatedPercentage: + "$serde_json::private::Number": "85" + violations: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + carbonIntensity: + result: "185" + exceededThreshold: + result: "true" + hasWasteViolations: + result: "true" + hasWaterViolations: + result: "false" + percentOverThreshold: + result: "23.33333333333333333333333333" + industryRiskTable: + id: industryRiskTable + input: + audits: + lastAuditDate: 2025-01-15 + previousFindings: + "$serde_json::private::Number": "3" + resolvedFindings: + "$serde_json::private::Number": "2" + emissions: + carbonDioxideMetricTons: + "$serde_json::private::Number": "18500" + methaneMetricTons: + "$serde_json::private::Number": "120" + nitrousOxideMetricTons: + "$serde_json::private::Number": "45" + industry: manufacturing + location: + city: Detroit + country: United States + region: midwest + production: + units: million_units + volume: + "$serde_json::private::Number": "100" + waste: + hazardousWasteMetricTons: + "$serde_json::private::Number": "50" + nonHazardousWasteMetricTons: + "$serde_json::private::Number": "350" + recycledPercentage: + "$serde_json::private::Number": "22" + violations: + "$serde_json::private::Number": "1" + water: + consumptionKiloliters: + "$serde_json::private::Number": "250000" + treatedPercentage: + "$serde_json::private::Number": "85" + violations: + "$serde_json::private::Number": "0" + name: industryRiskAssessment + order: + "$serde_json::private::Number": "1" + output: + assessment: + emissionThreshold: + "$serde_json::private::Number": "150" + industryRiskLevel: medium + audits: + lastAuditDate: 2025-01-15 + previousFindings: + "$serde_json::private::Number": "3" + resolvedFindings: + "$serde_json::private::Number": "2" + emissions: + carbonDioxideMetricTons: + "$serde_json::private::Number": "18500" + methaneMetricTons: + "$serde_json::private::Number": "120" + nitrousOxideMetricTons: + "$serde_json::private::Number": "45" + industry: manufacturing + location: + city: Detroit + country: United States + region: midwest + production: + units: million_units + volume: + "$serde_json::private::Number": "100" + waste: + hazardousWasteMetricTons: + "$serde_json::private::Number": "50" + nonHazardousWasteMetricTons: + "$serde_json::private::Number": "350" + recycledPercentage: + "$serde_json::private::Number": "22" + violations: + "$serde_json::private::Number": "1" + water: + consumptionKiloliters: + "$serde_json::private::Number": "250000" + treatedPercentage: + "$serde_json::private::Number": "85" + violations: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + industry: manufacturing + location.region: midwest + rule: + _id: rule2 + "industry[industry]": "'manufacturing', 'automotive', 'construction'" + "location.region[region]": "" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + audits: + lastAuditDate: 2025-01-15 + previousFindings: + "$serde_json::private::Number": "3" + resolvedFindings: + "$serde_json::private::Number": "2" + emissions: + carbonDioxideMetricTons: + "$serde_json::private::Number": "18500" + methaneMetricTons: + "$serde_json::private::Number": "120" + nitrousOxideMetricTons: + "$serde_json::private::Number": "45" + industry: manufacturing + location: + city: Detroit + country: United States + region: midwest + production: + units: million_units + volume: + "$serde_json::private::Number": "100" + waste: + hazardousWasteMetricTons: + "$serde_json::private::Number": "50" + nonHazardousWasteMetricTons: + "$serde_json::private::Number": "350" + recycledPercentage: + "$serde_json::private::Number": "22" + violations: + "$serde_json::private::Number": "1" + water: + consumptionKiloliters: + "$serde_json::private::Number": "250000" + treatedPercentage: + "$serde_json::private::Number": "85" + violations: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-default_0.snap b/core/engine/tests/snapshots/engine__expression-default_0.snap new file mode 100644 index 00000000..abbc07d8 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-default_0.snap @@ -0,0 +1,41 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + sum: + "$serde_json::private::Number": "3" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "2" + extra: This should not pass through + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + sum: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: + sum: + result: "3" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "2" + extra: This should not pass through + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-default_1.snap b/core/engine/tests/snapshots/engine__expression-default_1.snap new file mode 100644 index 00000000..53740f31 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-default_1.snap @@ -0,0 +1,43 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + sum: + "$serde_json::private::Number": "8" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "5" + b: + "$serde_json::private::Number": "3" + sum: + "$serde_json::private::Number": "100" + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + sum: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + sum: + result: "8" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "5" + b: + "$serde_json::private::Number": "3" + sum: + "$serde_json::private::Number": "100" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-default_2.snap b/core/engine/tests/snapshots/engine__expression-default_2.snap new file mode 100644 index 00000000..7d611a11 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-default_2.snap @@ -0,0 +1,47 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + sum: + "$serde_json::private::Number": "30" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "10" + b: + "$serde_json::private::Number": "20" + c: + "$serde_json::private::Number": "30" + d: + "$serde_json::private::Number": "40" + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + sum: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + sum: + result: "30" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "10" + b: + "$serde_json::private::Number": "20" + c: + "$serde_json::private::Number": "30" + d: + "$serde_json::private::Number": "40" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-default_3.snap b/core/engine/tests/snapshots/engine__expression-default_3.snap new file mode 100644 index 00000000..707be199 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-default_3.snap @@ -0,0 +1,41 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + sum: + "$serde_json::private::Number": "10" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "7" + b: + "$serde_json::private::Number": "3" + passThrough: This should not appear in output + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + sum: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: + sum: + result: "10" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "7" + b: + "$serde_json::private::Number": "3" + passThrough: This should not appear in output + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-default_4.snap b/core/engine/tests/snapshots/engine__expression-default_4.snap new file mode 100644 index 00000000..6886c512 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-default_4.snap @@ -0,0 +1,41 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + sum: + "$serde_json::private::Number": "1" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "-4" + b: + "$serde_json::private::Number": "5" + negative: true + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + sum: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: + sum: + result: "1" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "-4" + b: + "$serde_json::private::Number": "5" + negative: true + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-fields_0.snap b/core/engine/tests/snapshots/engine__expression-fields_0.snap new file mode 100644 index 00000000..349a1972 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-fields_0.snap @@ -0,0 +1,65 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + customer: + age: + "$serde_json::private::Number": "30" + firstName: John + fullName: John Doe + lastName: Doe + order: + id: ORD-001 + total: + "$serde_json::private::Number": "100" +trace: + expression-node-1: + id: expression-node-1 + input: + customer: + age: + "$serde_json::private::Number": "30" + firstName: John + lastName: Doe + order: + id: ORD-001 + total: + "$serde_json::private::Number": "100" + name: customerFullName + order: + "$serde_json::private::Number": "1" + output: + customer: + age: + "$serde_json::private::Number": "30" + firstName: John + fullName: John Doe + lastName: Doe + order: + id: ORD-001 + total: + "$serde_json::private::Number": "100" + performance: "[perf]" + traceData: + fullName: + result: "\"John Doe\"" + input-node: + id: input-node + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + age: + "$serde_json::private::Number": "30" + firstName: John + lastName: Doe + order: + id: ORD-001 + total: + "$serde_json::private::Number": "100" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-fields_1.snap b/core/engine/tests/snapshots/engine__expression-fields_1.snap new file mode 100644 index 00000000..9612f989 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-fields_1.snap @@ -0,0 +1,65 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + customer: + age: + "$serde_json::private::Number": "25" + firstName: Jane + fullName: Jane Smith + lastName: Smith + order: + id: ORD-002 + total: + "$serde_json::private::Number": "150" +trace: + expression-node-1: + id: expression-node-1 + input: + customer: + age: + "$serde_json::private::Number": "25" + firstName: Jane + lastName: Smith + order: + id: ORD-002 + total: + "$serde_json::private::Number": "150" + name: customerFullName + order: + "$serde_json::private::Number": "1" + output: + customer: + age: + "$serde_json::private::Number": "25" + firstName: Jane + fullName: Jane Smith + lastName: Smith + order: + id: ORD-002 + total: + "$serde_json::private::Number": "150" + performance: "[perf]" + traceData: + fullName: + result: "\"Jane Smith\"" + input-node: + id: input-node + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + age: + "$serde_json::private::Number": "25" + firstName: Jane + lastName: Smith + order: + id: ORD-002 + total: + "$serde_json::private::Number": "150" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-loop_0.snap b/core/engine/tests/snapshots/engine__expression-loop_0.snap new file mode 100644 index 00000000..0dd840f7 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-loop_0.snap @@ -0,0 +1,115 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + cart: + customerId: CUST-001 + items: + - name: Apple + price: + "$serde_json::private::Number": "0.5" + quantity: + "$serde_json::private::Number": "3" + totalPrice: + "$serde_json::private::Number": "1.5" + - name: Banana + price: + "$serde_json::private::Number": "0.3" + quantity: + "$serde_json::private::Number": "5" + totalPrice: + "$serde_json::private::Number": "1.5" + - name: Orange + price: + "$serde_json::private::Number": "0.7" + quantity: + "$serde_json::private::Number": "2" + totalPrice: + "$serde_json::private::Number": "1.4" +trace: + expression-node-1: + id: expression-node-1 + input: + cart: + customerId: CUST-001 + items: + - name: Apple + price: + "$serde_json::private::Number": "0.5" + quantity: + "$serde_json::private::Number": "3" + - name: Banana + price: + "$serde_json::private::Number": "0.3" + quantity: + "$serde_json::private::Number": "5" + - name: Orange + price: + "$serde_json::private::Number": "0.7" + quantity: + "$serde_json::private::Number": "2" + name: calculateItemTotal + order: + "$serde_json::private::Number": "1" + output: + cart: + customerId: CUST-001 + items: + - name: Apple + price: + "$serde_json::private::Number": "0.5" + quantity: + "$serde_json::private::Number": "3" + totalPrice: + "$serde_json::private::Number": "1.5" + - name: Banana + price: + "$serde_json::private::Number": "0.3" + quantity: + "$serde_json::private::Number": "5" + totalPrice: + "$serde_json::private::Number": "1.5" + - name: Orange + price: + "$serde_json::private::Number": "0.7" + quantity: + "$serde_json::private::Number": "2" + totalPrice: + "$serde_json::private::Number": "1.4" + performance: "[perf]" + traceData: + - totalPrice: + result: "1.5" + - totalPrice: + result: "1.5" + - totalPrice: + result: "1.4" + input-node: + id: input-node + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + cart: + customerId: CUST-001 + items: + - name: Apple + price: + "$serde_json::private::Number": "0.5" + quantity: + "$serde_json::private::Number": "3" + - name: Banana + price: + "$serde_json::private::Number": "0.3" + quantity: + "$serde_json::private::Number": "5" + - name: Orange + price: + "$serde_json::private::Number": "0.7" + quantity: + "$serde_json::private::Number": "2" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_0.snap b/core/engine/tests/snapshots/engine__expression-passthrough_0.snap new file mode 100644 index 00000000..94c78cb3 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-passthrough_0.snap @@ -0,0 +1,49 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "2" + sum: + "$serde_json::private::Number": "3" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "2" + sum: [] + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "2" + sum: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: + sum: + result: "3" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "2" + sum: [] + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_1.snap b/core/engine/tests/snapshots/engine__expression-passthrough_1.snap new file mode 100644 index 00000000..e2e91185 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-passthrough_1.snap @@ -0,0 +1,51 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + a: + "$serde_json::private::Number": "5" + b: + "$serde_json::private::Number": "3" + sum: + "$serde_json::private::Number": "8" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "5" + b: + "$serde_json::private::Number": "3" + sum: + "$serde_json::private::Number": "100" + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + a: + "$serde_json::private::Number": "5" + b: + "$serde_json::private::Number": "3" + sum: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + sum: + result: "8" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "5" + b: + "$serde_json::private::Number": "3" + sum: + "$serde_json::private::Number": "100" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_2.snap b/core/engine/tests/snapshots/engine__expression-passthrough_2.snap new file mode 100644 index 00000000..841a38ec --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-passthrough_2.snap @@ -0,0 +1,51 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + a: + "$serde_json::private::Number": "10" + b: + "$serde_json::private::Number": "20" + extra: This should pass through + sum: + "$serde_json::private::Number": "30" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "10" + b: + "$serde_json::private::Number": "20" + extra: This should pass through + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + a: + "$serde_json::private::Number": "10" + b: + "$serde_json::private::Number": "20" + extra: This should pass through + sum: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + sum: + result: "30" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "10" + b: + "$serde_json::private::Number": "20" + extra: This should pass through + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_3.snap b/core/engine/tests/snapshots/engine__expression-passthrough_3.snap new file mode 100644 index 00000000..a5012336 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-passthrough_3.snap @@ -0,0 +1,53 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + a: + "$serde_json::private::Number": "7" + b: + "$serde_json::private::Number": "3" + passThrough: Test + sum: + "$serde_json::private::Number": "10" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "7" + b: + "$serde_json::private::Number": "3" + passThrough: Test + sum: Original + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + a: + "$serde_json::private::Number": "7" + b: + "$serde_json::private::Number": "3" + passThrough: Test + sum: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: + sum: + result: "10" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "7" + b: + "$serde_json::private::Number": "3" + passThrough: Test + sum: Original + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_4.snap b/core/engine/tests/snapshots/engine__expression-passthrough_4.snap new file mode 100644 index 00000000..49ec48e9 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-passthrough_4.snap @@ -0,0 +1,63 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "1" + c: + "$serde_json::private::Number": "3" + d: + "$serde_json::private::Number": "4" + sum: + "$serde_json::private::Number": "2" +trace: + 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: + id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 + input: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "1" + c: + "$serde_json::private::Number": "3" + d: + "$serde_json::private::Number": "4" + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "1" + c: + "$serde_json::private::Number": "3" + d: + "$serde_json::private::Number": "4" + sum: + "$serde_json::private::Number": "2" + performance: "[perf]" + traceData: + sum: + result: "2" + deced339-bace-452a-8db0-777f038bffe8: + id: deced339-bace-452a-8db0-777f038bffe8 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + a: + "$serde_json::private::Number": "1" + b: + "$serde_json::private::Number": "1" + c: + "$serde_json::private::Number": "3" + d: + "$serde_json::private::Number": "4" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-table-map_0.snap b/core/engine/tests/snapshots/engine__expression-table-map_0.snap new file mode 100644 index 00000000..56ccf031 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-table-map_0.snap @@ -0,0 +1,263 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + customer: + country: US + name: John Doe + exprItems: + - amount: + "$serde_json::private::Number": "50" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + exprItemsSum: + "$serde_json::private::Number": "50" + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + tblItemsSum: + "$serde_json::private::Number": "1050" +trace: + 3814877d-0169-45dc-b4f5-5f9eade2e4f1: + id: 3814877d-0169-45dc-b4f5-5f9eade2e4f1 + input: + customer: + country: US + name: John Doe + exprItems: + - amount: + "$serde_json::private::Number": "50" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + name: sum + order: + "$serde_json::private::Number": "2" + output: + customer: + country: US + name: John Doe + exprItems: + - amount: + "$serde_json::private::Number": "50" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + exprItemsSum: + "$serde_json::private::Number": "50" + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + performance: "[perf]" + traceData: + exprItemsSum: + result: "50" + 5f56e61b-5687-4758-8524-8121df13b2ba: + id: 5f56e61b-5687-4758-8524-8121df13b2ba + input: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + name: expr + order: + "$serde_json::private::Number": "1" + output: + customer: + country: US + name: John Doe + exprItems: + - amount: + "$serde_json::private::Number": "50" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + performance: "[perf]" + traceData: + - discount: + result: "5" + 8ceca45e-e6ff-4613-984c-5846e53c5a39: + id: 8ceca45e-e6ff-4613-984c-5846e53c5a39 + input: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + name: sum + order: + "$serde_json::private::Number": "4" + output: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + tblItemsSum: + "$serde_json::private::Number": "1050" + performance: "[perf]" + traceData: + tblItemsSum: + result: "1050" + b8ebb212-e290-4131-9703-0bb7b1fd2328: + id: b8ebb212-e290-4131-9703-0bb7b1fd2328 + input: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + name: table + order: + "$serde_json::private::Number": "3" + output: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: fd81538a-7451-4eb7-a25c-01c3afbebbdf + be2a55f4-cdd8-482e-b53c-a947cbb7d7a0: + id: be2a55f4-cdd8-482e-b53c-a947cbb7d7a0 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories + name: Mouse + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-table-map_1.snap b/core/engine/tests/snapshots/engine__expression-table-map_1.snap new file mode 100644 index 00000000..897216d2 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-table-map_1.snap @@ -0,0 +1,224 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + customer: + country: US + name: John Doe + exprItems: [] + exprItemsSum: + "$serde_json::private::Number": "0" + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + tblItemsSum: + "$serde_json::private::Number": "1050" +trace: + 3814877d-0169-45dc-b4f5-5f9eade2e4f1: + id: 3814877d-0169-45dc-b4f5-5f9eade2e4f1 + input: + customer: + country: US + name: John Doe + exprItems: [] + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + name: sum + order: + "$serde_json::private::Number": "2" + output: + customer: + country: US + name: John Doe + exprItems: [] + exprItemsSum: + "$serde_json::private::Number": "0" + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + performance: "[perf]" + traceData: + exprItemsSum: + result: "0" + 5f56e61b-5687-4758-8524-8121df13b2ba: + id: 5f56e61b-5687-4758-8524-8121df13b2ba + input: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + name: expr + order: + "$serde_json::private::Number": "1" + output: + customer: + country: US + name: John Doe + exprItems: [] + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + performance: "[perf]" + traceData: [] + 8ceca45e-e6ff-4613-984c-5846e53c5a39: + id: 8ceca45e-e6ff-4613-984c-5846e53c5a39 + input: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + name: sum + order: + "$serde_json::private::Number": "4" + output: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + tblItemsSum: + "$serde_json::private::Number": "1050" + performance: "[perf]" + traceData: + tblItemsSum: + result: "1050" + b8ebb212-e290-4131-9703-0bb7b1fd2328: + id: b8ebb212-e290-4131-9703-0bb7b1fd2328 + input: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + name: table + order: + "$serde_json::private::Number": "3" + output: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + performance: "[perf]" + traceData: [] + be2a55f4-cdd8-482e-b53c-a947cbb7d7a0: + id: be2a55f4-cdd8-482e-b53c-a947cbb7d7a0 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "50" + group: accessories_new + name: Mouse + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__expression-table-map_2.snap b/core/engine/tests/snapshots/engine__expression-table-map_2.snap new file mode 100644 index 00000000..619240c2 --- /dev/null +++ b/core/engine/tests/snapshots/engine__expression-table-map_2.snap @@ -0,0 +1,263 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + customer: + country: US + name: John Doe + exprItems: + - amount: + "$serde_json::private::Number": "51" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + exprItemsSum: + "$serde_json::private::Number": "51" + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + tblItemsSum: + "$serde_json::private::Number": "1051" +trace: + 3814877d-0169-45dc-b4f5-5f9eade2e4f1: + id: 3814877d-0169-45dc-b4f5-5f9eade2e4f1 + input: + customer: + country: US + name: John Doe + exprItems: + - amount: + "$serde_json::private::Number": "51" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + name: sum + order: + "$serde_json::private::Number": "2" + output: + customer: + country: US + name: John Doe + exprItems: + - amount: + "$serde_json::private::Number": "51" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + exprItemsSum: + "$serde_json::private::Number": "51" + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + performance: "[perf]" + traceData: + exprItemsSum: + result: "51" + 5f56e61b-5687-4758-8524-8121df13b2ba: + id: 5f56e61b-5687-4758-8524-8121df13b2ba + input: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + name: expr + order: + "$serde_json::private::Number": "1" + output: + customer: + country: US + name: John Doe + exprItems: + - amount: + "$serde_json::private::Number": "51" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + performance: "[perf]" + traceData: + - discount: + result: "5" + 8ceca45e-e6ff-4613-984c-5846e53c5a39: + id: 8ceca45e-e6ff-4613-984c-5846e53c5a39 + input: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + name: sum + order: + "$serde_json::private::Number": "4" + output: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + tblItemsSum: + "$serde_json::private::Number": "1051" + performance: "[perf]" + traceData: + tblItemsSum: + result: "1051" + b8ebb212-e290-4131-9703-0bb7b1fd2328: + id: b8ebb212-e290-4131-9703-0bb7b1fd2328 + input: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + name: table + order: + "$serde_json::private::Number": "3" + output: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + tblItems: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + discount: + "$serde_json::private::Number": "5" + group: accessories + name: Mouse + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: fd81538a-7451-4eb7-a25c-01c3afbebbdf + be2a55f4-cdd8-482e-b53c-a947cbb7d7a0: + id: be2a55f4-cdd8-482e-b53c-a947cbb7d7a0 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + country: US + name: John Doe + items: + - amount: + "$serde_json::private::Number": "1000" + group: electronics + name: Laptop + - amount: + "$serde_json::private::Number": "51" + group: accessories + name: Mouse + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__flash-sale-eligibility_0.snap b/core/engine/tests/snapshots/engine__flash-sale-eligibility_0.snap new file mode 100644 index 00000000..8bfa5c1a --- /dev/null +++ b/core/engine/tests/snapshots/engine__flash-sale-eligibility_0.snap @@ -0,0 +1,276 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + discountPercentage: + "$serde_json::private::Number": "15" + eligibilityReason: Product fully qualifies for flash sale + initialCheckReason: Sufficient inventory and margin + isEligibleForFlashSale: true + isInSeason: true + isQualifiedSeller: true + passesInitialCheck: true + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + seasonReason: Summer product in summer months + seasonalityFactor: + "$serde_json::private::Number": "1.2" + sellerFactor: + "$serde_json::private::Number": "1.5" + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" +trace: + checkInventoryAndMargin: + id: checkInventoryAndMargin + input: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" + name: checkInventoryAndMargin + order: + "$serde_json::private::Number": "1" + output: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + initialCheckReason: Sufficient inventory and margin + passesInitialCheck: true + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + currentInventory: + "$serde_json::private::Number": "75" + profitMargin: + "$serde_json::private::Number": "0.28" + rule: + _id: r1 + "currentInventory[i1]": ">= 50" + "profitMargin[i2]": ">= 0.25" + checkSeasonality: + id: checkSeasonality + input: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + initialCheckReason: Sufficient inventory and margin + passesInitialCheck: true + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" + name: checkSeasonality + order: + "$serde_json::private::Number": "2" + output: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + initialCheckReason: Sufficient inventory and margin + isInSeason: true + passesInitialCheck: true + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + seasonReason: Summer product in summer months + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + currentMonth: + "$serde_json::private::Number": "7" + season: summer + rule: + _id: r1 + "currentMonth[i2]": "6, 7, 8" + "season[i1]": "'summer'" + checkSellerQuality: + id: checkSellerQuality + input: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + initialCheckReason: Sufficient inventory and margin + isInSeason: true + passesInitialCheck: true + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + seasonReason: Summer product in summer months + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" + name: checkSellerQuality + order: + "$serde_json::private::Number": "3" + output: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + initialCheckReason: Sufficient inventory and margin + isInSeason: true + isQualifiedSeller: true + passesInitialCheck: true + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + seasonReason: Summer product in summer months + seasonalityFactor: + "$serde_json::private::Number": "1.2" + sellerFactor: + "$serde_json::private::Number": "1.5" + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" + performance: "[perf]" + traceData: + isQualifiedSeller: + result: "true" + seasonalityFactor: + result: "1.2" + sellerFactor: + result: "1.5" + determineEligibility: + id: determineEligibility + input: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + initialCheckReason: Sufficient inventory and margin + isInSeason: true + isQualifiedSeller: true + passesInitialCheck: true + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + seasonReason: Summer product in summer months + seasonalityFactor: + "$serde_json::private::Number": "1.2" + sellerFactor: + "$serde_json::private::Number": "1.5" + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" + name: determineEligibility + order: + "$serde_json::private::Number": "4" + output: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + discountPercentage: + "$serde_json::private::Number": "15" + eligibilityReason: Product fully qualifies for flash sale + initialCheckReason: Sufficient inventory and margin + isEligibleForFlashSale: true + isInSeason: true + isQualifiedSeller: true + passesInitialCheck: true + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + seasonReason: Summer product in summer months + seasonalityFactor: + "$serde_json::private::Number": "1.2" + sellerFactor: + "$serde_json::private::Number": "1.5" + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + isInSeason: true + isQualifiedSeller: true + passesInitialCheck: true + rule: + _id: r1 + "isInSeason[i2]": isInSeason == true + "isQualifiedSeller[i3]": isQualifiedSeller == true + "passesInitialCheck[i1]": passesInitialCheck == true + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + category: Electronics + currentInventory: + "$serde_json::private::Number": "75" + currentMonth: + "$serde_json::private::Number": "7" + productId: PROD-12345 + profitMargin: + "$serde_json::private::Number": "0.28" + season: summer + sellerHistoricalSales: + "$serde_json::private::Number": "2500" + sellerRating: + "$serde_json::private::Number": "4.5" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__flight-ancillary-recommendations_0.snap b/core/engine/tests/snapshots/engine__flight-ancillary-recommendations_0.snap new file mode 100644 index 00000000..6180fb02 --- /dev/null +++ b/core/engine/tests/snapshots/engine__flight-ancillary-recommendations_0.snap @@ -0,0 +1,630 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + recommendations: + - priority: + "$serde_json::private::Number": "5" + productType: lounge + - priority: + "$serde_json::private::Number": "4" + productType: priority_boarding + - priority: + "$serde_json::private::Number": "3" + productType: wifi + - priority: + "$serde_json::private::Number": "4" + productType: lounge + - priority: + "$serde_json::private::Number": "3" + productType: travel_insurance + - priority: + "$serde_json::private::Number": "2" + productType: premium_meal + - priority: + "$serde_json::private::Number": "4" + productType: fast_track_security +trace: + 8cb0ce16-c426-4988-b39f-d122499bc1fd: + id: 8cb0ce16-c426-4988-b39f-d122499bc1fd + input: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + flightDurationCategory: long + hasBoughtBaggage: false + hasBoughtLounge: false + hasBoughtMeals: false + hasBoughtSeats: true + isPremiumCustomer: true + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + recommendations: + additional: + - priority: + "$serde_json::private::Number": "4" + productType: lounge + - priority: + "$serde_json::private::Number": "3" + productType: travel_insurance + - priority: + "$serde_json::private::Number": "2" + productType: premium_meal + - priority: + "$serde_json::private::Number": "4" + productType: fast_track_security + base: + - priority: + "$serde_json::private::Number": "5" + productType: lounge + - priority: + "$serde_json::private::Number": "4" + productType: priority_boarding + - priority: + "$serde_json::private::Number": "3" + productType: wifi + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + name: join_recommendations + order: + "$serde_json::private::Number": "5" + output: + recommendations: + - priority: + "$serde_json::private::Number": "5" + productType: lounge + - priority: + "$serde_json::private::Number": "4" + productType: priority_boarding + - priority: + "$serde_json::private::Number": "3" + productType: wifi + - priority: + "$serde_json::private::Number": "4" + productType: lounge + - priority: + "$serde_json::private::Number": "3" + productType: travel_insurance + - priority: + "$serde_json::private::Number": "2" + productType: premium_meal + - priority: + "$serde_json::private::Number": "4" + productType: fast_track_security + performance: "[perf]" + traceData: + recommendations: + result: "[{\"productType\":\"lounge\",\"priority\":5},{\"productType\":\"priority_boarding\",\"priority\":4},{\"productType\":\"wifi\",\"priority\":3},{\"priority\":4,\"productType\":\"lounge\"},{\"productType\":\"travel_insurance\",\"priority\":3},{\"productType\":\"premium_meal\",\"priority\":2},{\"productType\":\"fast_track_security\",\"priority\":4}]" + dt1: + id: dt1 + input: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + name: categorize_flight_duration + order: + "$serde_json::private::Number": "1" + output: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + flightDurationCategory: long + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + route.flightDurationMinutes: + "$serde_json::private::Number": "480" + rule: + _id: r1-1 + "route.flightDurationMinutes[i1-1]": ">= 240" + dt2: + id: dt2 + input: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + flightDurationCategory: long + hasBoughtBaggage: false + hasBoughtLounge: false + hasBoughtMeals: false + hasBoughtSeats: true + isPremiumCustomer: true + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + name: base_recommendations + order: + "$serde_json::private::Number": "3" + output: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + flightDurationCategory: long + hasBoughtBaggage: false + hasBoughtLounge: false + hasBoughtMeals: false + hasBoughtSeats: true + isPremiumCustomer: true + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + recommendations: + base: + - priority: + "$serde_json::private::Number": "5" + productType: lounge + - priority: + "$serde_json::private::Number": "4" + productType: priority_boarding + - priority: + "$serde_json::private::Number": "3" + productType: wifi + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: + flightDurationCategory: long + travelPurpose: business + rule: + _id: r2-1 + "flightDurationCategory[i2-2]": "'long'" + "travelPurpose[i2-1]": "'business'" + - index: + "$serde_json::private::Number": "1" + reference_map: + flightDurationCategory: long + travelPurpose: business + rule: + _id: r2-2 + "flightDurationCategory[i2-2]": "'medium', 'long'" + "travelPurpose[i2-1]": "'business'" + - index: + "$serde_json::private::Number": "2" + reference_map: + flightDurationCategory: long + travelPurpose: business + rule: + _id: r2-3 + "flightDurationCategory[i2-2]": "" + "travelPurpose[i2-1]": "'business'" + dt3: + id: dt3 + input: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + flightDurationCategory: long + hasBoughtBaggage: false + hasBoughtLounge: false + hasBoughtMeals: false + hasBoughtSeats: true + isPremiumCustomer: true + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + recommendations: + base: + - priority: + "$serde_json::private::Number": "5" + productType: lounge + - priority: + "$serde_json::private::Number": "4" + productType: priority_boarding + - priority: + "$serde_json::private::Number": "3" + productType: wifi + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + name: additional_recommendations + order: + "$serde_json::private::Number": "4" + output: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + flightDurationCategory: long + hasBoughtBaggage: false + hasBoughtLounge: false + hasBoughtMeals: false + hasBoughtSeats: true + isPremiumCustomer: true + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + recommendations: + additional: + - priority: + "$serde_json::private::Number": "4" + productType: lounge + - priority: + "$serde_json::private::Number": "3" + productType: travel_insurance + - priority: + "$serde_json::private::Number": "2" + productType: premium_meal + - priority: + "$serde_json::private::Number": "4" + productType: fast_track_security + base: + - priority: + "$serde_json::private::Number": "5" + productType: lounge + - priority: + "$serde_json::private::Number": "4" + productType: priority_boarding + - priority: + "$serde_json::private::Number": "3" + productType: wifi + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: r3-1 + - index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: r3-2 + - index: + "$serde_json::private::Number": "2" + reference_map: {} + rule: + _id: r3-3 + - index: + "$serde_json::private::Number": "3" + reference_map: {} + rule: + _id: r3-4 + ex1: + id: ex1 + input: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + flightDurationCategory: long + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + name: calculate_customer_attributes + order: + "$serde_json::private::Number": "2" + output: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + flightDurationCategory: long + hasBoughtBaggage: false + hasBoughtLounge: false + hasBoughtMeals: false + hasBoughtSeats: true + isPremiumCustomer: true + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: + hasBoughtBaggage: + result: "false" + hasBoughtLounge: + result: "false" + hasBoughtMeals: + result: "false" + hasBoughtSeats: + result: "true" + isPremiumCustomer: + result: "true" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customerProfile: + id: cust-12345 + loyaltyTier: gold + preferredCurrency: USD + preferredLanguage: en + travelFrequency: frequent + previousPurchases: + - bookingId: bkg-9876 + productDetails: + amount: + "$serde_json::private::Number": "35" + seatType: extra_legroom + productType: seat + purchaseDate: "2024-12-10T14:22:00Z" + - bookingId: bkg-8765 + productDetails: + amount: + "$serde_json::private::Number": "19.99" + packageType: full_flight + productType: wifi + purchaseDate: "2024-11-05T09:15:00Z" + route: + departureTime: "2025-04-15T08:30:00Z" + destination: international + flightDurationMinutes: + "$serde_json::private::Number": "480" + hasAirportLounge: true + origin: JFK + returnTime: "2025-04-22T15:45:00Z" + travelPurpose: business + tripDetails: + cabinClass: economy + dateFlexibility: fixed + passengers: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__flight-dispatch-decision-system_0.snap b/core/engine/tests/snapshots/engine__flight-dispatch-decision-system_0.snap new file mode 100644 index 00000000..e1ea9cf9 --- /dev/null +++ b/core/engine/tests/snapshots/engine__flight-dispatch-decision-system_0.snap @@ -0,0 +1,752 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + dispatchReasons: + - flag: false + reason: Extreme wind and low visibility + dispatchSummary: Flight dispatch denied + failedCriteria: + - weather + isDispatchable: false +trace: + aircraftEligibility: + id: aircraftEligibility + input: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + name: aircraftEligibility + order: + "$serde_json::private::Number": "4" + output: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + dispatch: + aircraft: + flag: true + reason: Aircraft is operational + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + aircraft.fuelReserves: + "$serde_json::private::Number": "1.5" + aircraft.maintenanceRequired: false + rule: + _id: rule3 + "aircraft.fuelReserves[fuelReserves]": "" + "aircraft.maintenanceRequired[maintenance]": "" + crewEligibility: + id: crewEligibility + input: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + name: crewEligibility + order: + "$serde_json::private::Number": "5" + output: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + dispatch: + crew: + flag: true + reason: Crew requirements satisfied + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + crew.restCompliant: true + len(crew.members): + "$serde_json::private::Number": "3" + rule: + _id: rule3 + "crew.restCompliant[restCompliant]": "" + "len(crew.members)[crewCount]": "" + dispatchSummary: + id: dispatchSummary + input: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + dispatch: + aircraft: + flag: true + reason: Aircraft is operational + crew: + flag: true + reason: Crew requirements satisfied + weather: + flag: false + reason: Extreme wind and low visibility + weight: + flag: true + reason: Weight within acceptable limits + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + name: dispatchSummary + order: + "$serde_json::private::Number": "6" + output: + dispatchReasons: + - flag: false + reason: Extreme wind and low visibility + dispatchSummary: Flight dispatch denied + failedCriteria: + - weather + isDispatchable: false + performance: "[perf]" + traceData: + dispatchReasons: + result: "[{\"flag\":false,\"reason\":\"Extreme wind and low visibility\"}]" + dispatchSummary: + result: "\"Flight dispatch denied\"" + failedCriteria: + result: "[\"weather\"]" + isDispatchable: + result: "false" + inputNode: + id: inputNode + input: ~ + name: flightDispatchRequest + order: + "$serde_json::private::Number": "0" + output: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + performance: "[perf]" + traceData: ~ + weatherEligibility: + id: weatherEligibility + input: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + name: weatherEligibility + order: + "$serde_json::private::Number": "3" + output: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + dispatch: + weather: + flag: false + reason: Extreme wind and low visibility + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + weather.visibility: + "$serde_json::private::Number": "6500" + weather.windSpeed: + "$serde_json::private::Number": "90" + rule: + _id: rule1 + "weather.visibility[visibility]": "< 10000" + "weather.windSpeed[windSpeed]": "> 45" + weightCalculations: + id: weightCalculations + input: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + name: weightCalculations + order: + "$serde_json::private::Number": "1" + output: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + performance: "[perf]" + traceData: + estimatedTakeoffWeight: + result: "44850" + passengerWeight: + result: "850" + totalCargo: + result: "2500" + totalPassengers: + result: "10" + weightEligibility: + id: weightEligibility + input: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + name: weightEligibility + order: + "$serde_json::private::Number": "2" + output: + aircraft: + emptyWeight: + "$serde_json::private::Number": "41500" + fuelReserves: + "$serde_json::private::Number": "1.5" + maintenanceRequired: false + maxTakeoffWeight: + "$serde_json::private::Number": "78000" + type: B737-800 + crew: + members: + - C001 + - C002 + - C003 + restCompliant: true + dispatch: + weight: + flag: true + reason: Weight within acceptable limits + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + flight: + destination: JFK + number: FL123 + origin: LAX + scheduledDeparture: "2025-03-19T08:00:00Z" + manifest: + cargoWeight: + "$serde_json::private::Number": "2500" + passengers: + - P001 + - P002 + - P003 + - P004 + - P005 + - P006 + - P007 + - P008 + - P009 + - P010 + passengerWeight: + "$serde_json::private::Number": "850" + totalCargo: + "$serde_json::private::Number": "2500" + totalPassengers: + "$serde_json::private::Number": "10" + weather: + precipitation: light + temperature: + "$serde_json::private::Number": "15" + visibility: + "$serde_json::private::Number": "6500" + windSpeed: + "$serde_json::private::Number": "90" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + estimatedTakeoffWeight: + "$serde_json::private::Number": "44850" + rule: + _id: rule2 + "estimatedTakeoffWeight[takeoffWeight]": "" diff --git a/core/engine/tests/snapshots/engine__flight-rebooking-fee-calculator_0.snap b/core/engine/tests/snapshots/engine__flight-rebooking-fee-calculator_0.snap new file mode 100644 index 00000000..01ebc5ec --- /dev/null +++ b/core/engine/tests/snapshots/engine__flight-rebooking-fee-calculator_0.snap @@ -0,0 +1,309 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + modificationFee: + allowed: true + description: Standard modification fee + finalFee: + "$serde_json::private::Number": "188" +trace: + dt1: + id: dt1 + input: + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + name: baseFeeCalculation + order: + "$serde_json::private::Number": "1" + output: + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + modificationFee: + baseFee: + "$serde_json::private::Number": "200" + baseFeeReason: High fee for Economy with 3-14 days to departure + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "7" + reference_map: + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + rule: + _id: r1-8 + "daysToDeparture[i1-2]": "> 3 and <= 14" + "fareClass[i1-1]": "'Economy'" + dt2: + id: dt2 + input: + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + modificationFee: + baseFee: + "$serde_json::private::Number": "200" + baseFeeReason: High fee for Economy with 3-14 days to departure + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + name: frequencyMultiplier + order: + "$serde_json::private::Number": "2" + output: + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + modificationFee: + baseFee: + "$serde_json::private::Number": "200" + baseFeeReason: High fee for Economy with 3-14 days to departure + frequencyMultiplier: + "$serde_json::private::Number": "1.25" + frequencyReason: 25% surcharge for 2-3 changes + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + changeFrequency: + "$serde_json::private::Number": "2" + rule: + _id: r2-2 + "changeFrequency[i2-1]": "> 1 and <= 3" + dt3: + id: dt3 + input: + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + modificationFee: + baseFee: + "$serde_json::private::Number": "200" + baseFeeReason: High fee for Economy with 3-14 days to departure + frequencyMultiplier: + "$serde_json::private::Number": "1.25" + frequencyReason: 25% surcharge for 2-3 changes + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + name: loyaltyFactor + order: + "$serde_json::private::Number": "3" + output: + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + modificationFee: + baseFee: + "$serde_json::private::Number": "200" + baseFeeReason: High fee for Economy with 3-14 days to departure + frequencyMultiplier: + "$serde_json::private::Number": "1.25" + frequencyReason: 25% surcharge for 2-3 changes + loyaltyFactor: + "$serde_json::private::Number": "0.75" + loyaltyReason: Silver members receive 25% discount + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + loyaltyTier: Silver + rule: + _id: r3-3 + "loyaltyTier[i3-1]": "'Silver'" + dt4: + id: dt4 + input: + adjustedFee: + "$serde_json::private::Number": "188" + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + modificationFee: + baseFee: + "$serde_json::private::Number": "200" + baseFeeReason: High fee for Economy with 3-14 days to departure + frequencyMultiplier: + "$serde_json::private::Number": "1.25" + frequencyReason: 25% surcharge for 2-3 changes + loyaltyFactor: + "$serde_json::private::Number": "0.75" + loyaltyReason: Silver members receive 25% discount + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + name: finalFeeAssessment + order: + "$serde_json::private::Number": "5" + output: + modificationFee: + allowed: true + description: Standard modification fee + finalFee: + "$serde_json::private::Number": "188" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: {} + rule: + _id: r4-5 + ex1: + id: ex1 + input: + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + modificationFee: + baseFee: + "$serde_json::private::Number": "200" + baseFeeReason: High fee for Economy with 3-14 days to departure + frequencyMultiplier: + "$serde_json::private::Number": "1.25" + frequencyReason: 25% surcharge for 2-3 changes + loyaltyFactor: + "$serde_json::private::Number": "0.75" + loyaltyReason: Silver members receive 25% discount + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + name: calculateAdjustedFee + order: + "$serde_json::private::Number": "4" + output: + adjustedFee: + "$serde_json::private::Number": "188" + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + modificationFee: + baseFee: + "$serde_json::private::Number": "200" + baseFeeReason: High fee for Economy with 3-14 days to departure + frequencyMultiplier: + "$serde_json::private::Number": "1.25" + frequencyReason: 25% surcharge for 2-3 changes + loyaltyFactor: + "$serde_json::private::Number": "0.75" + loyaltyReason: Silver members receive 25% discount + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + performance: "[perf]" + traceData: + adjustedFee: + result: "188" + ip1: + id: ip1 + input: ~ + name: bookingModificationRequest + order: + "$serde_json::private::Number": "0" + output: + bookingId: BK-12345678 + changeFrequency: + "$serde_json::private::Number": "2" + daysToDeparture: + "$serde_json::private::Number": "12" + fareClass: Economy + loyaltyTier: Silver + newDepartureDate: "2025-05-20T14:15:00Z" + originalDepartureDate: "2025-05-15T10:30:00Z" + passengerDetails: + firstName: Jane + lastName: Smith + loyaltyNumber: LM789012 + loyaltyTier: Silver + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__government-assistance_0.snap b/core/engine/tests/snapshots/engine__government-assistance_0.snap new file mode 100644 index 00000000..cf56b02a --- /dev/null +++ b/core/engine/tests/snapshots/engine__government-assistance_0.snap @@ -0,0 +1,143 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + applicant: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "28000" + householdSize: + "$serde_json::private::Number": "3" + specialCircumstances: + hasDisability: true + isCaregiver: false + isVeteran: false + eligibility: + assignedProgram: full-assistance-enhanced + baseEligible: true + eligible: true + programType: full-assistance +trace: + incomeEligibility: + id: incomeEligibility + input: + applicant: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "28000" + householdSize: + "$serde_json::private::Number": "3" + specialCircumstances: + hasDisability: true + isCaregiver: false + isVeteran: false + name: Income Eligibility + order: + "$serde_json::private::Number": "1" + output: + applicant: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "28000" + householdSize: + "$serde_json::private::Number": "3" + specialCircumstances: + hasDisability: true + isCaregiver: false + isVeteran: false + eligibility: + baseEligible: true + programType: full-assistance + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + applicant.age: + "$serde_json::private::Number": "35" + applicant.annualIncome: + "$serde_json::private::Number": "28000" + applicant.householdSize: + "$serde_json::private::Number": "3" + rule: + _id: rule2 + "applicant.age[age]": ">= 18" + "applicant.annualIncome[income]": "<= 30000" + "applicant.householdSize[householdSize]": "> 2 and <= 4" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + applicant: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "28000" + householdSize: + "$serde_json::private::Number": "3" + specialCircumstances: + hasDisability: true + isCaregiver: false + isVeteran: false + performance: "[perf]" + traceData: ~ + specialCircumstances: + id: specialCircumstances + input: + applicant: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "28000" + householdSize: + "$serde_json::private::Number": "3" + specialCircumstances: + hasDisability: true + isCaregiver: false + isVeteran: false + eligibility: + baseEligible: true + programType: full-assistance + name: Special Circumstances + order: + "$serde_json::private::Number": "2" + output: + applicant: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "28000" + householdSize: + "$serde_json::private::Number": "3" + specialCircumstances: + hasDisability: true + isCaregiver: false + isVeteran: false + eligibility: + assignedProgram: full-assistance-enhanced + baseEligible: true + eligible: true + programType: full-assistance + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + applicant.specialCircumstances.hasDisability: true + applicant.specialCircumstances.isCaregiver: false + applicant.specialCircumstances.isVeteran: false + eligibility.baseEligible: true + rule: + _id: special4 + "applicant.specialCircumstances.hasDisability[hasDisability]": "true" + "applicant.specialCircumstances.isCaregiver[isCaregiver]": "" + "applicant.specialCircumstances.isVeteran[isVeteran]": "" + "eligibility.baseEligible[baseEligibility]": "true" diff --git a/core/engine/tests/snapshots/engine__grant-funding-distribution_0.snap b/core/engine/tests/snapshots/engine__grant-funding-distribution_0.snap new file mode 100644 index 00000000..7daa2c8f --- /dev/null +++ b/core/engine/tests/snapshots/engine__grant-funding-distribution_0.snap @@ -0,0 +1,287 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + fundingPercentage: + "$serde_json::private::Number": "76" + fundingStatus: Approved + grantAmount: + "$serde_json::private::Number": "57000" + maxPossibleAmount: + "$serde_json::private::Number": "57000" +trace: + budgetConstraint: + id: budgetConstraint + input: + application: + applicantQualifications: medium + id: GR-2025-0042 + impactMetrics: + beneficiaries: + "$serde_json::private::Number": "1200" + communityNeedScore: + "$serde_json::private::Number": "85" + innovationScore: + "$serde_json::private::Number": "72" + overallScore: + "$serde_json::private::Number": "75" + sustainabilityScore: + "$serde_json::private::Number": "68" + minimumViableAmount: + "$serde_json::private::Number": "50000" + organizationName: Community Health Initiative + projectScope: high + projectTitle: Rural Healthcare Access Program + requestedAmount: + "$serde_json::private::Number": "75000" + budgetConstraints: + allocatedAmount: + "$serde_json::private::Number": "325000" + allocationRatio: + "$serde_json::private::Number": "0.65" + maxAwardAmount: + "$serde_json::private::Number": "100000" + totalBudget: + "$serde_json::private::Number": "500000" + evaluation: + baseFundingRatio: + "$serde_json::private::Number": "0.8" + fundingPriority: high + name: budget_constraint + order: + "$serde_json::private::Number": "2" + output: + application: + applicantQualifications: medium + id: GR-2025-0042 + impactMetrics: + beneficiaries: + "$serde_json::private::Number": "1200" + communityNeedScore: + "$serde_json::private::Number": "85" + innovationScore: + "$serde_json::private::Number": "72" + overallScore: + "$serde_json::private::Number": "75" + sustainabilityScore: + "$serde_json::private::Number": "68" + minimumViableAmount: + "$serde_json::private::Number": "50000" + organizationName: Community Health Initiative + projectScope: high + projectTitle: Rural Healthcare Access Program + requestedAmount: + "$serde_json::private::Number": "75000" + budgetConstraints: + allocatedAmount: + "$serde_json::private::Number": "325000" + allocationRatio: + "$serde_json::private::Number": "0.65" + maxAwardAmount: + "$serde_json::private::Number": "100000" + totalBudget: + "$serde_json::private::Number": "500000" + evaluation: + adjustmentFactor: + "$serde_json::private::Number": "0.95" + baseFundingRatio: + "$serde_json::private::Number": "0.8" + fundingPriority: high + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + budgetConstraints.allocationRatio: + "$serde_json::private::Number": "0.65" + evaluation.fundingPriority: high + rule: + _id: bc1 + "budgetConstraints.allocationRatio[i2]": "< 0.75" + "evaluation.fundingPriority[i1]": "'high'" + fundingCalculation: + id: fundingCalculation + input: + application: + applicantQualifications: medium + id: GR-2025-0042 + impactMetrics: + beneficiaries: + "$serde_json::private::Number": "1200" + communityNeedScore: + "$serde_json::private::Number": "85" + innovationScore: + "$serde_json::private::Number": "72" + overallScore: + "$serde_json::private::Number": "75" + sustainabilityScore: + "$serde_json::private::Number": "68" + minimumViableAmount: + "$serde_json::private::Number": "50000" + organizationName: Community Health Initiative + projectScope: high + projectTitle: Rural Healthcare Access Program + requestedAmount: + "$serde_json::private::Number": "75000" + budgetConstraints: + allocatedAmount: + "$serde_json::private::Number": "325000" + allocationRatio: + "$serde_json::private::Number": "0.65" + maxAwardAmount: + "$serde_json::private::Number": "100000" + totalBudget: + "$serde_json::private::Number": "500000" + evaluation: + adjustmentFactor: + "$serde_json::private::Number": "0.95" + baseFundingRatio: + "$serde_json::private::Number": "0.8" + fundingPriority: high + name: funding_calculation + order: + "$serde_json::private::Number": "3" + output: + fundingPercentage: + "$serde_json::private::Number": "76" + fundingStatus: Approved + grantAmount: + "$serde_json::private::Number": "57000" + maxPossibleAmount: + "$serde_json::private::Number": "57000" + performance: "[perf]" + traceData: + fundingPercentage: + result: "76" + fundingStatus: + result: "\"Approved\"" + grantAmount: + result: "57000" + maxPossibleAmount: + result: "57000" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + application: + applicantQualifications: medium + id: GR-2025-0042 + impactMetrics: + beneficiaries: + "$serde_json::private::Number": "1200" + communityNeedScore: + "$serde_json::private::Number": "85" + innovationScore: + "$serde_json::private::Number": "72" + overallScore: + "$serde_json::private::Number": "75" + sustainabilityScore: + "$serde_json::private::Number": "68" + minimumViableAmount: + "$serde_json::private::Number": "50000" + organizationName: Community Health Initiative + projectScope: high + projectTitle: Rural Healthcare Access Program + requestedAmount: + "$serde_json::private::Number": "75000" + budgetConstraints: + allocatedAmount: + "$serde_json::private::Number": "325000" + allocationRatio: + "$serde_json::private::Number": "0.65" + maxAwardAmount: + "$serde_json::private::Number": "100000" + totalBudget: + "$serde_json::private::Number": "500000" + performance: "[perf]" + traceData: ~ + projectEvaluation: + id: projectEvaluation + input: + application: + applicantQualifications: medium + id: GR-2025-0042 + impactMetrics: + beneficiaries: + "$serde_json::private::Number": "1200" + communityNeedScore: + "$serde_json::private::Number": "85" + innovationScore: + "$serde_json::private::Number": "72" + overallScore: + "$serde_json::private::Number": "75" + sustainabilityScore: + "$serde_json::private::Number": "68" + minimumViableAmount: + "$serde_json::private::Number": "50000" + organizationName: Community Health Initiative + projectScope: high + projectTitle: Rural Healthcare Access Program + requestedAmount: + "$serde_json::private::Number": "75000" + budgetConstraints: + allocatedAmount: + "$serde_json::private::Number": "325000" + allocationRatio: + "$serde_json::private::Number": "0.65" + maxAwardAmount: + "$serde_json::private::Number": "100000" + totalBudget: + "$serde_json::private::Number": "500000" + name: project_evaluation + order: + "$serde_json::private::Number": "1" + output: + application: + applicantQualifications: medium + id: GR-2025-0042 + impactMetrics: + beneficiaries: + "$serde_json::private::Number": "1200" + communityNeedScore: + "$serde_json::private::Number": "85" + innovationScore: + "$serde_json::private::Number": "72" + overallScore: + "$serde_json::private::Number": "75" + sustainabilityScore: + "$serde_json::private::Number": "68" + minimumViableAmount: + "$serde_json::private::Number": "50000" + organizationName: Community Health Initiative + projectScope: high + projectTitle: Rural Healthcare Access Program + requestedAmount: + "$serde_json::private::Number": "75000" + budgetConstraints: + allocatedAmount: + "$serde_json::private::Number": "325000" + allocationRatio: + "$serde_json::private::Number": "0.65" + maxAwardAmount: + "$serde_json::private::Number": "100000" + totalBudget: + "$serde_json::private::Number": "500000" + evaluation: + baseFundingRatio: + "$serde_json::private::Number": "0.8" + fundingPriority: high + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + application.applicantQualifications: medium + application.impactMetrics.overallScore: + "$serde_json::private::Number": "75" + application.projectScope: high + rule: + _id: r2 + "application.applicantQualifications[i2]": "'medium'" + "application.impactMetrics.overallScore[i3]": ">= 70" + "application.projectScope[i1]": "'high'" diff --git a/core/engine/tests/snapshots/engine__hazardous-materials-management-system_0.snap b/core/engine/tests/snapshots/engine__hazardous-materials-management-system_0.snap new file mode 100644 index 00000000..e42439b5 --- /dev/null +++ b/core/engine/tests/snapshots/engine__hazardous-materials-management-system_0.snap @@ -0,0 +1,164 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + complianceRequirements: Safety data sheets must accompany shipment + handlingProcedure: "Avoid contact with skin and eyes, neutralizing agents must be readily available" + hazardClassification: Class B - Corrosive + hazardLevel: high + location: Lab-B42 + material: Sulfuric Acid + permitRequired: "false" + quantity: + "$serde_json::private::Number": "75" + recommendedStorageZone: yellow-zone + reportingRequired: "false" + requiredEquipment: "Chemical-resistant gloves, face shield, apron, boots" + state: liquid + storageLimit: + "$serde_json::private::Number": "1000" + transportMode: road +trace: + handlingRequirementsTable: + id: handlingRequirementsTable + input: + hazardClassification: Class B - Corrosive + hazardLevel: high + location: Lab-B42 + material: Sulfuric Acid + quantity: + "$serde_json::private::Number": "75" + recommendedStorageZone: yellow-zone + state: liquid + transportMode: road + name: Handling Requirements + order: + "$serde_json::private::Number": "2" + output: + handlingProcedure: "Avoid contact with skin and eyes, neutralizing agents must be readily available" + hazardClassification: Class B - Corrosive + hazardLevel: high + location: Lab-B42 + material: Sulfuric Acid + quantity: + "$serde_json::private::Number": "75" + recommendedStorageZone: yellow-zone + requiredEquipment: "Chemical-resistant gloves, face shield, apron, boots" + state: liquid + storageLimit: + "$serde_json::private::Number": "1000" + transportMode: road + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + hazardClassification: Class B - Corrosive + hazardLevel: high + rule: + _id: rule2 + "hazardClassification[hazardClass]": "'Class B - Corrosive'" + "hazardLevel[hazardLevel]": "'high'" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + location: Lab-B42 + material: Sulfuric Acid + quantity: + "$serde_json::private::Number": "75" + state: liquid + transportMode: road + performance: "[perf]" + traceData: ~ + materialClassificationTable: + id: materialClassificationTable + input: + location: Lab-B42 + material: Sulfuric Acid + quantity: + "$serde_json::private::Number": "75" + state: liquid + transportMode: road + name: Material Classification + order: + "$serde_json::private::Number": "1" + output: + hazardClassification: Class B - Corrosive + hazardLevel: high + location: Lab-B42 + material: Sulfuric Acid + quantity: + "$serde_json::private::Number": "75" + recommendedStorageZone: yellow-zone + state: liquid + transportMode: road + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + lower(material): sulfuric acid + quantity: + "$serde_json::private::Number": "75" + state: liquid + rule: + _id: rule2 + "lower(material)[materialType]": "some(['corrosive', 'acid', 'base'], contains($, #))" + "quantity[materialQuantity]": "" + "state[materialState]": "" + regulatoryComplianceTable: + id: regulatoryComplianceTable + input: + handlingProcedure: "Avoid contact with skin and eyes, neutralizing agents must be readily available" + hazardClassification: Class B - Corrosive + hazardLevel: high + location: Lab-B42 + material: Sulfuric Acid + quantity: + "$serde_json::private::Number": "75" + recommendedStorageZone: yellow-zone + requiredEquipment: "Chemical-resistant gloves, face shield, apron, boots" + state: liquid + storageLimit: + "$serde_json::private::Number": "1000" + transportMode: road + name: Regulatory Compliance + order: + "$serde_json::private::Number": "3" + output: + complianceRequirements: Safety data sheets must accompany shipment + handlingProcedure: "Avoid contact with skin and eyes, neutralizing agents must be readily available" + hazardClassification: Class B - Corrosive + hazardLevel: high + location: Lab-B42 + material: Sulfuric Acid + permitRequired: "false" + quantity: + "$serde_json::private::Number": "75" + recommendedStorageZone: yellow-zone + reportingRequired: "false" + requiredEquipment: "Chemical-resistant gloves, face shield, apron, boots" + state: liquid + storageLimit: + "$serde_json::private::Number": "1000" + transportMode: road + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + hazardClassification: Class B - Corrosive + quantity: + "$serde_json::private::Number": "75" + transportMode: road + rule: + _id: rule5 + "hazardClassification[hazardClass]": "'Class A - Flammable', 'Class B - Corrosive', 'Class C - Toxic', 'Class F - Oxidizer'" + "quantity[quantityCheck]": "<= 100" + "transportMode[transportMode]": "'road', 'rail', 'sea'" diff --git a/core/engine/tests/snapshots/engine__immigration-eligibility-evaluator_0.snap b/core/engine/tests/snapshots/engine__immigration-eligibility-evaluator_0.snap new file mode 100644 index 00000000..8883486a --- /dev/null +++ b/core/engine/tests/snapshots/engine__immigration-eligibility-evaluator_0.snap @@ -0,0 +1,791 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + additionalFactorsReason: In-demand skills + additionalFactorsScore: + "$serde_json::private::Number": "80" + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + experienceReason: Significant work experience + experienceScore: + "$serde_json::private::Number": "80" + finalReason: Application meets criteria + finalStatus: approved + languageReason: Advanced language proficiency + languageScore: + "$serde_json::private::Number": "75" + overallScore: + "$serde_json::private::Number": "85.83333333333333333333333333" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" +trace: + additionalFactorsTable: + id: additionalFactorsTable + input: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + experienceReason: Significant work experience + experienceScore: + "$serde_json::private::Number": "80" + languageReason: Advanced language proficiency + languageScore: + "$serde_json::private::Number": "75" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + name: assessAdditionalFactors + order: + "$serde_json::private::Number": "6" + output: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + additionalFactorsReason: In-demand skills + additionalFactorsScore: + "$serde_json::private::Number": "80" + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + experienceReason: Significant work experience + experienceScore: + "$serde_json::private::Number": "80" + languageReason: Advanced language proficiency + languageScore: + "$serde_json::private::Number": "75" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + qualifications.familyConnections: false + qualifications.skillsInDemand: true + rule: + _id: rule2 + "qualifications.familyConnections[i6-2]": "false" + "qualifications.skillsInDemand[i6-1]": "true" + backgroundCheck: + id: backgroundCheck + input: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + name: evaluateBackground + order: + "$serde_json::private::Number": "2" + output: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "5" + reference_map: + background.criminalHistory: false + background.immigrationViolations: false + background.previousVisaRejections: + "$serde_json::private::Number": "0" + background.securityConcerns: false + rule: + _id: rule6 + "background.criminalHistory[i2-1]": "false" + "background.immigrationViolations[i2-2]": "false" + "background.previousVisaRejections[i2-4]": "0" + "background.securityConcerns[i2-3]": "false" + documentationCheck: + id: documentationCheck + input: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + name: verifyDocumentation + order: + "$serde_json::private::Number": "1" + output: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + documentation.medicalCheckComplete: true + documentation.passportValid: true + documentation.proofOfFundsProvided: true + documentation.visaApplicationComplete: true + rule: + _id: rule5 + "documentation.medicalCheckComplete[i1-4]": "true" + "documentation.passportValid[i1-1]": "true" + "documentation.proofOfFundsProvided[i1-3]": "true" + "documentation.visaApplicationComplete[i1-2]": "true" + educationTable: + id: educationTable + input: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + name: assessEducation + order: + "$serde_json::private::Number": "3" + output: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + qualifications.educationLevel: master + rule: + _id: rule2 + "qualifications.educationLevel[i3-1]": "\"master\"" + experienceTable: + id: experienceTable + input: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + name: assessWorkExperience + order: + "$serde_json::private::Number": "4" + output: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + experienceReason: Significant work experience + experienceScore: + "$serde_json::private::Number": "80" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + qualifications.workExperienceYears: + "$serde_json::private::Number": "8" + rule: + _id: rule2 + "qualifications.workExperienceYears[i4-1]": ">= 7" + input: + id: input + input: ~ + name: immigrationApplication + order: + "$serde_json::private::Number": "0" + output: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: ~ + languageTable: + id: languageTable + input: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + experienceReason: Significant work experience + experienceScore: + "$serde_json::private::Number": "80" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + name: assessLanguage + order: + "$serde_json::private::Number": "5" + output: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + experienceReason: Significant work experience + experienceScore: + "$serde_json::private::Number": "80" + languageReason: Advanced language proficiency + languageScore: + "$serde_json::private::Number": "75" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + qualifications.languageProficiency: advanced + rule: + _id: rule2 + "qualifications.languageProficiency[i5-1]": "\"advanced\"" + overallAssessment: + id: overallAssessment + input: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + additionalFactorsReason: In-demand skills + additionalFactorsScore: + "$serde_json::private::Number": "80" + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + experienceReason: Significant work experience + experienceScore: + "$serde_json::private::Number": "80" + languageReason: Advanced language proficiency + languageScore: + "$serde_json::private::Number": "75" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + name: finalAssessment + order: + "$serde_json::private::Number": "7" + output: + applicant: + currentResidence: France + dateOfBirth: 1985-05-15 + fullName: Jane Smith + nationality: United Kingdom + assessment: + additionalFactorsReason: In-demand skills + additionalFactorsScore: + "$serde_json::private::Number": "80" + backgroundReason: Background check clear + backgroundScore: + "$serde_json::private::Number": "100" + backgroundStatus: pending + documentationReason: Documentation complete + documentationScore: + "$serde_json::private::Number": "100" + documentationStatus: pending + educationReason: Advanced education + educationScore: + "$serde_json::private::Number": "80" + experienceReason: Significant work experience + experienceScore: + "$serde_json::private::Number": "80" + finalReason: Application meets criteria + finalStatus: approved + languageReason: Advanced language proficiency + languageScore: + "$serde_json::private::Number": "75" + overallScore: + "$serde_json::private::Number": "85.83333333333333333333333333" + background: + criminalHistory: false + immigrationViolations: false + previousVisaRejections: + "$serde_json::private::Number": "0" + securityConcerns: false + documentation: + medicalCheckComplete: true + passportValid: true + proofOfFundsProvided: true + supportingDocuments: + - Reference Letter + - Property Deed + - Bank Statements + visaApplicationComplete: true + qualifications: + educationLevel: master + familyConnections: false + languageProficiency: advanced + skillsInDemand: true + workExperienceYears: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + (assessment.documentationScore + assessment.backgroundScore + assessment.educationScore + assessment.experienceScore + assessment.languageScore + assessment.additionalFactorsScore) / 6: + "$serde_json::private::Number": "85.83333333333333333333333333" + assessment.backgroundStatus: pending + assessment.documentationStatus: pending + rule: + "(assessment.documentationScore + assessment.backgroundScore + assessment.educationScore + assessment.experienceScore + assessment.languageScore + assessment.additionalFactorsScore) / 6[i7-3]": ">= 70" + _id: rule5 + "assessment.backgroundStatus[i7-2]": "" + "assessment.documentationStatus[i7-1]": "" diff --git a/core/engine/tests/snapshots/engine__import-duties-calculator_0.snap b/core/engine/tests/snapshots/engine__import-duties-calculator_0.snap new file mode 100644 index 00000000..4d7b2e3a --- /dev/null +++ b/core/engine/tests/snapshots/engine__import-duties-calculator_0.snap @@ -0,0 +1,207 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + additionalFees: + "$serde_json::private::Number": "0" + baseDuty: + "$serde_json::private::Number": "180" + countryAdjustment: + "$serde_json::private::Number": "225" + dutyRate: + "$serde_json::private::Number": "0.1875" + minDuty: + "$serde_json::private::Number": "225" + preferentialDiscount: + "$serde_json::private::Number": "225" + totalDuty: + "$serde_json::private::Number": "225" +trace: + country_rules: + id: country_rules + input: + classification: + baseRate: + "$serde_json::private::Number": "0.15" + category: High-Tech Electronics + destination: + country: US + origin: + country: CN + hasFTA: false + preferentialTreatment: false + product: + category: electronics + hsCode: "851712" + value: + "$serde_json::private::Number": "1200" + weight: + "$serde_json::private::Number": "0.8" + name: country_rules + order: + "$serde_json::private::Number": "2" + output: + classification: + baseRate: + "$serde_json::private::Number": "0.15" + category: High-Tech Electronics + countryRules: + hasSanctions: false + multiplier: + "$serde_json::private::Number": "1.25" + destination: + country: US + origin: + country: CN + hasFTA: false + preferentialTreatment: false + product: + category: electronics + hsCode: "851712" + value: + "$serde_json::private::Number": "1200" + weight: + "$serde_json::private::Number": "0.8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + destination.country: US + origin.country: CN + origin.hasFTA: false + rule: + _id: cr-1 + "destination.country[i-destination]": "'US'" + "origin.country[i-origin]": "'CN'" + "origin.hasFTA[i-hasFTA]": "false" + duty_calculation: + id: duty_calculation + input: + classification: + baseRate: + "$serde_json::private::Number": "0.15" + category: High-Tech Electronics + countryRules: + hasSanctions: false + multiplier: + "$serde_json::private::Number": "1.25" + destination: + country: US + origin: + country: CN + hasFTA: false + preferentialTreatment: false + product: + category: electronics + hsCode: "851712" + value: + "$serde_json::private::Number": "1200" + weight: + "$serde_json::private::Number": "0.8" + name: duty_calculation + order: + "$serde_json::private::Number": "3" + output: + additionalFees: + "$serde_json::private::Number": "0" + baseDuty: + "$serde_json::private::Number": "180" + countryAdjustment: + "$serde_json::private::Number": "225" + dutyRate: + "$serde_json::private::Number": "0.1875" + minDuty: + "$serde_json::private::Number": "225" + preferentialDiscount: + "$serde_json::private::Number": "225" + totalDuty: + "$serde_json::private::Number": "225" + performance: "[perf]" + traceData: + additionalFees: + result: "0" + baseDuty: + result: "180" + countryAdjustment: + result: "225" + dutyRate: + result: "0.1875" + minDuty: + result: "225" + preferentialDiscount: + result: "225" + totalDuty: + result: "225" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + destination: + country: US + origin: + country: CN + hasFTA: false + preferentialTreatment: false + product: + category: electronics + hsCode: "851712" + value: + "$serde_json::private::Number": "1200" + weight: + "$serde_json::private::Number": "0.8" + performance: "[perf]" + traceData: ~ + product_classification: + id: product_classification + input: + destination: + country: US + origin: + country: CN + hasFTA: false + preferentialTreatment: false + product: + category: electronics + hsCode: "851712" + value: + "$serde_json::private::Number": "1200" + weight: + "$serde_json::private::Number": "0.8" + name: product_classification + order: + "$serde_json::private::Number": "1" + output: + classification: + baseRate: + "$serde_json::private::Number": "0.15" + category: High-Tech Electronics + destination: + country: US + origin: + country: CN + hasFTA: false + preferentialTreatment: false + product: + category: electronics + hsCode: "851712" + value: + "$serde_json::private::Number": "1200" + weight: + "$serde_json::private::Number": "0.8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + product.category: electronics + product.hsCode: "851712" + rule: + _id: pc-1 + "product.category[i-category]": "'electronics'" + "product.hsCode[i-hsCode]": "startsWith($, '85')" diff --git a/core/engine/tests/snapshots/engine__insurance-agent-commission_0.snap b/core/engine/tests/snapshots/engine__insurance-agent-commission_0.snap new file mode 100644 index 00000000..1d8178ea --- /dev/null +++ b/core/engine/tests/snapshots/engine__insurance-agent-commission_0.snap @@ -0,0 +1,122 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + baseCommission: + "$serde_json::private::Number": "360" + baseCommissionRate: + "$serde_json::private::Number": "0.18" + finalCommission: + "$serde_json::private::Number": "450" + performanceTier: gold + policyType: home + premiumAmount: + "$serde_json::private::Number": "2000" + tierMultiplier: + "$serde_json::private::Number": "1.25" +trace: + dt1: + id: dt1 + input: + performanceTier: gold + policyType: home + premiumAmount: + "$serde_json::private::Number": "2000" + name: baseCommissionRates + order: + "$serde_json::private::Number": "1" + output: + baseCommissionRate: + "$serde_json::private::Number": "0.18" + performanceTier: gold + policyType: home + premiumAmount: + "$serde_json::private::Number": "2000" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + policyType: home + premiumAmount: + "$serde_json::private::Number": "2000" + rule: + _id: r1-4 + "policyType[i1-1]": "'home'" + "premiumAmount[i1-2]": "> 1500" + dt2: + id: dt2 + input: + baseCommission: + "$serde_json::private::Number": "360" + baseCommissionRate: + "$serde_json::private::Number": "0.18" + performanceTier: gold + policyType: home + premiumAmount: + "$serde_json::private::Number": "2000" + name: performanceTierMultipliers + order: + "$serde_json::private::Number": "3" + output: + baseCommission: + "$serde_json::private::Number": "360" + baseCommissionRate: + "$serde_json::private::Number": "0.18" + finalCommission: + "$serde_json::private::Number": "450" + performanceTier: gold + policyType: home + premiumAmount: + "$serde_json::private::Number": "2000" + tierMultiplier: + "$serde_json::private::Number": "1.25" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + performanceTier: gold + rule: + _id: r2-2 + "performanceTier[i2-1]": "'gold'" + ex1: + id: ex1 + input: + baseCommissionRate: + "$serde_json::private::Number": "0.18" + performanceTier: gold + policyType: home + premiumAmount: + "$serde_json::private::Number": "2000" + name: calculateBaseCommission + order: + "$serde_json::private::Number": "2" + output: + baseCommission: + "$serde_json::private::Number": "360" + baseCommissionRate: + "$serde_json::private::Number": "0.18" + performanceTier: gold + policyType: home + premiumAmount: + "$serde_json::private::Number": "2000" + performance: "[perf]" + traceData: + baseCommission: + result: "360" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + performanceTier: gold + policyType: home + premiumAmount: + "$serde_json::private::Number": "2000" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__insurance-breakdown_0.snap b/core/engine/tests/snapshots/engine__insurance-breakdown_0.snap new file mode 100644 index 00000000..82929145 --- /dev/null +++ b/core/engine/tests/snapshots/engine__insurance-breakdown_0.snap @@ -0,0 +1,181 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "83" + - key: gst + title: GST + value: + "$serde_json::private::Number": "10.3" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "20" +trace: + 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d: + id: 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d + input: + country: CA + coverage: + pi: 1M + pl: 10M + name: Fees + order: + "$serde_json::private::Number": "4" + output: + fee: + broker: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: 629a0bff-c452-474c-b5a0-0b5c0b7d0880 + 453ed4ec-8754-4768-823a-0741e12926ee: + id: 453ed4ec-8754-4768-823a-0741e12926ee + input: + base: + pi: + "$serde_json::private::Number": "63" + pl: + "$serde_json::private::Number": "20" + fee: + broker: + "$serde_json::private::Number": "20" + tax: + gst: + "$serde_json::private::Number": "10" + name: Aggregator + order: + "$serde_json::private::Number": "5" + output: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "83" + - key: gst + title: GST + value: + "$serde_json::private::Number": "10.3" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + log: [] + 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6: + id: 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + country: CA + coverage: + pi: 1M + pl: 10M + performance: "[perf]" + traceData: ~ + 52d501fa-5089-471a-81e1-9d604b6b864d: + id: 52d501fa-5089-471a-81e1-9d604b6b864d + input: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "83" + - key: gst + title: GST + value: + "$serde_json::private::Number": "10.3" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "20" + name: Response + order: + "$serde_json::private::Number": "6" + output: ~ + performance: "[perf]" + traceData: ~ + 831e22b5-93c4-4963-9d21-8af157dd1606: + id: 831e22b5-93c4-4963-9d21-8af157dd1606 + input: + country: CA + coverage: + pi: 1M + pl: 10M + name: PL Base + order: + "$serde_json::private::Number": "1" + output: + base: + pl: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + coverage.pl: 10M + rule: + _id: e4ffd222-ef9c-4ab7-a5ef-6f6ff0c6f1c2 + "coverage.pl[6d179b45-a0b7-4c85-8324-73058f3def42]": "\"10M\"" + b9d38a6e-2d57-483c-9765-66d97b940a04: + id: b9d38a6e-2d57-483c-9765-66d97b940a04 + input: + country: CA + coverage: + pi: 1M + pl: 10M + name: GST + order: + "$serde_json::private::Number": "2" + output: + tax: + gst: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + country: CA + state: ~ + rule: + _id: 35babb81-b350-4445-853f-3877892910f9 + "country[5ca5e8d1-8339-483b-9c81-cdd34a4fb953]": "\"CA\"" + "state[8342de09-7a13-4d3b-82f9-156e2381817d]": "" + ebec39cc-ac87-4145-ae5d-744759a37268: + id: ebec39cc-ac87-4145-ae5d-744759a37268 + input: + country: CA + coverage: + pi: 1M + pl: 10M + name: PI Base + order: + "$serde_json::private::Number": "3" + output: + base: + pi: + "$serde_json::private::Number": "63" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + coverage.pi: 1M + rule: + _id: 900c2af2-8b75-414f-b365-97fbf2ddf28f + "coverage.pi[ec711970-6b90-492f-8b5b-4a6e7cbf3088]": "\"1M\"" diff --git a/core/engine/tests/snapshots/engine__insurance-breakdown_1.snap b/core/engine/tests/snapshots/engine__insurance-breakdown_1.snap new file mode 100644 index 00000000..fb58f918 --- /dev/null +++ b/core/engine/tests/snapshots/engine__insurance-breakdown_1.snap @@ -0,0 +1,176 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "83" + - key: gst + title: GST + value: + "$serde_json::private::Number": "0" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "20" +trace: + 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d: + id: 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d + input: + coverage: + pi: 1M + pl: 10M + name: Fees + order: + "$serde_json::private::Number": "4" + output: + fee: + broker: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: 629a0bff-c452-474c-b5a0-0b5c0b7d0880 + 453ed4ec-8754-4768-823a-0741e12926ee: + id: 453ed4ec-8754-4768-823a-0741e12926ee + input: + base: + pi: + "$serde_json::private::Number": "63" + pl: + "$serde_json::private::Number": "20" + fee: + broker: + "$serde_json::private::Number": "20" + tax: + gst: + "$serde_json::private::Number": "0" + name: Aggregator + order: + "$serde_json::private::Number": "5" + output: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "83" + - key: gst + title: GST + value: + "$serde_json::private::Number": "0" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + log: [] + 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6: + id: 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + coverage: + pi: 1M + pl: 10M + performance: "[perf]" + traceData: ~ + 52d501fa-5089-471a-81e1-9d604b6b864d: + id: 52d501fa-5089-471a-81e1-9d604b6b864d + input: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "83" + - key: gst + title: GST + value: + "$serde_json::private::Number": "0" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "20" + name: Response + order: + "$serde_json::private::Number": "6" + output: ~ + performance: "[perf]" + traceData: ~ + 831e22b5-93c4-4963-9d21-8af157dd1606: + id: 831e22b5-93c4-4963-9d21-8af157dd1606 + input: + coverage: + pi: 1M + pl: 10M + name: PL Base + order: + "$serde_json::private::Number": "1" + output: + base: + pl: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + coverage.pl: 10M + rule: + _id: e4ffd222-ef9c-4ab7-a5ef-6f6ff0c6f1c2 + "coverage.pl[6d179b45-a0b7-4c85-8324-73058f3def42]": "\"10M\"" + b9d38a6e-2d57-483c-9765-66d97b940a04: + id: b9d38a6e-2d57-483c-9765-66d97b940a04 + input: + coverage: + pi: 1M + pl: 10M + name: GST + order: + "$serde_json::private::Number": "2" + output: + tax: + gst: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + country: ~ + state: ~ + rule: + _id: 6670eccf-b410-4e6d-9979-da9f6bddc75d + "country[5ca5e8d1-8339-483b-9c81-cdd34a4fb953]": "" + "state[8342de09-7a13-4d3b-82f9-156e2381817d]": "" + ebec39cc-ac87-4145-ae5d-744759a37268: + id: ebec39cc-ac87-4145-ae5d-744759a37268 + input: + coverage: + pi: 1M + pl: 10M + name: PI Base + order: + "$serde_json::private::Number": "3" + output: + base: + pi: + "$serde_json::private::Number": "63" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + coverage.pi: 1M + rule: + _id: 900c2af2-8b75-414f-b365-97fbf2ddf28f + "coverage.pi[ec711970-6b90-492f-8b5b-4a6e7cbf3088]": "\"1M\"" diff --git a/core/engine/tests/snapshots/engine__insurance-breakdown_2.snap b/core/engine/tests/snapshots/engine__insurance-breakdown_2.snap new file mode 100644 index 00000000..c0414ebd --- /dev/null +++ b/core/engine/tests/snapshots/engine__insurance-breakdown_2.snap @@ -0,0 +1,176 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "125" + - key: gst + title: GST + value: + "$serde_json::private::Number": "0" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "45" +trace: + 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d: + id: 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d + input: + coverage: + pi: 2M + pl: 20M + name: Fees + order: + "$serde_json::private::Number": "4" + output: + fee: + broker: + "$serde_json::private::Number": "45" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: {} + rule: + _id: 4b4e7a3c-17f9-451b-9099-d938de7bfbbb + 453ed4ec-8754-4768-823a-0741e12926ee: + id: 453ed4ec-8754-4768-823a-0741e12926ee + input: + base: + pi: + "$serde_json::private::Number": "75" + pl: + "$serde_json::private::Number": "50" + fee: + broker: + "$serde_json::private::Number": "45" + tax: + gst: + "$serde_json::private::Number": "0" + name: Aggregator + order: + "$serde_json::private::Number": "5" + output: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "125" + - key: gst + title: GST + value: + "$serde_json::private::Number": "0" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "45" + performance: "[perf]" + traceData: + log: [] + 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6: + id: 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + coverage: + pi: 2M + pl: 20M + performance: "[perf]" + traceData: ~ + 52d501fa-5089-471a-81e1-9d604b6b864d: + id: 52d501fa-5089-471a-81e1-9d604b6b864d + input: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "125" + - key: gst + title: GST + value: + "$serde_json::private::Number": "0" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "45" + name: Response + order: + "$serde_json::private::Number": "6" + output: ~ + performance: "[perf]" + traceData: ~ + 831e22b5-93c4-4963-9d21-8af157dd1606: + id: 831e22b5-93c4-4963-9d21-8af157dd1606 + input: + coverage: + pi: 2M + pl: 20M + name: PL Base + order: + "$serde_json::private::Number": "1" + output: + base: + pl: + "$serde_json::private::Number": "50" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + coverage.pl: 20M + rule: + _id: 5a8986b1-27a3-4961-ab6d-e32fb773e083 + "coverage.pl[6d179b45-a0b7-4c85-8324-73058f3def42]": "\"20M\"" + b9d38a6e-2d57-483c-9765-66d97b940a04: + id: b9d38a6e-2d57-483c-9765-66d97b940a04 + input: + coverage: + pi: 2M + pl: 20M + name: GST + order: + "$serde_json::private::Number": "2" + output: + tax: + gst: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + country: ~ + state: ~ + rule: + _id: 6670eccf-b410-4e6d-9979-da9f6bddc75d + "country[5ca5e8d1-8339-483b-9c81-cdd34a4fb953]": "" + "state[8342de09-7a13-4d3b-82f9-156e2381817d]": "" + ebec39cc-ac87-4145-ae5d-744759a37268: + id: ebec39cc-ac87-4145-ae5d-744759a37268 + input: + coverage: + pi: 2M + pl: 20M + name: PI Base + order: + "$serde_json::private::Number": "3" + output: + base: + pi: + "$serde_json::private::Number": "75" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + coverage.pi: 2M + rule: + _id: 9b10a56d-ee99-40f3-aa30-85ed38f60ec7 + "coverage.pi[ec711970-6b90-492f-8b5b-4a6e7cbf3088]": "\"2M\"" diff --git a/core/engine/tests/snapshots/engine__insurance-breakdown_3.snap b/core/engine/tests/snapshots/engine__insurance-breakdown_3.snap new file mode 100644 index 00000000..8c79b235 --- /dev/null +++ b/core/engine/tests/snapshots/engine__insurance-breakdown_3.snap @@ -0,0 +1,181 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "95" + - key: gst + title: GST + value: + "$serde_json::private::Number": "12" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "25" +trace: + 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d: + id: 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d + input: + country: CA + coverage: + pi: 2M + pl: 10M + name: Fees + order: + "$serde_json::private::Number": "4" + output: + fee: + broker: + "$serde_json::private::Number": "25" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: 03ac3c59-9d38-431a-965f-d8da913b0100 + 453ed4ec-8754-4768-823a-0741e12926ee: + id: 453ed4ec-8754-4768-823a-0741e12926ee + input: + base: + pi: + "$serde_json::private::Number": "75" + pl: + "$serde_json::private::Number": "20" + fee: + broker: + "$serde_json::private::Number": "25" + tax: + gst: + "$serde_json::private::Number": "10" + name: Aggregator + order: + "$serde_json::private::Number": "5" + output: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "95" + - key: gst + title: GST + value: + "$serde_json::private::Number": "12" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "25" + performance: "[perf]" + traceData: + log: [] + 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6: + id: 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + country: CA + coverage: + pi: 2M + pl: 10M + performance: "[perf]" + traceData: ~ + 52d501fa-5089-471a-81e1-9d604b6b864d: + id: 52d501fa-5089-471a-81e1-9d604b6b864d + input: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "95" + - key: gst + title: GST + value: + "$serde_json::private::Number": "12" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "25" + name: Response + order: + "$serde_json::private::Number": "6" + output: ~ + performance: "[perf]" + traceData: ~ + 831e22b5-93c4-4963-9d21-8af157dd1606: + id: 831e22b5-93c4-4963-9d21-8af157dd1606 + input: + country: CA + coverage: + pi: 2M + pl: 10M + name: PL Base + order: + "$serde_json::private::Number": "1" + output: + base: + pl: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + coverage.pl: 10M + rule: + _id: e4ffd222-ef9c-4ab7-a5ef-6f6ff0c6f1c2 + "coverage.pl[6d179b45-a0b7-4c85-8324-73058f3def42]": "\"10M\"" + b9d38a6e-2d57-483c-9765-66d97b940a04: + id: b9d38a6e-2d57-483c-9765-66d97b940a04 + input: + country: CA + coverage: + pi: 2M + pl: 10M + name: GST + order: + "$serde_json::private::Number": "2" + output: + tax: + gst: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + country: CA + state: ~ + rule: + _id: 35babb81-b350-4445-853f-3877892910f9 + "country[5ca5e8d1-8339-483b-9c81-cdd34a4fb953]": "\"CA\"" + "state[8342de09-7a13-4d3b-82f9-156e2381817d]": "" + ebec39cc-ac87-4145-ae5d-744759a37268: + id: ebec39cc-ac87-4145-ae5d-744759a37268 + input: + country: CA + coverage: + pi: 2M + pl: 10M + name: PI Base + order: + "$serde_json::private::Number": "3" + output: + base: + pi: + "$serde_json::private::Number": "75" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + coverage.pi: 2M + rule: + _id: 9b10a56d-ee99-40f3-aa30-85ed38f60ec7 + "coverage.pi[ec711970-6b90-492f-8b5b-4a6e7cbf3088]": "\"2M\"" diff --git a/core/engine/tests/snapshots/engine__insurance-breakdown_4.snap b/core/engine/tests/snapshots/engine__insurance-breakdown_4.snap new file mode 100644 index 00000000..d92cb256 --- /dev/null +++ b/core/engine/tests/snapshots/engine__insurance-breakdown_4.snap @@ -0,0 +1,181 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "125" + - key: gst + title: GST + value: + "$serde_json::private::Number": "17" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "45" +trace: + 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d: + id: 0b998a2f-2b8d-45b4-8cea-13c731d0cd0d + input: + country: CA + coverage: + pi: 2M + pl: 20M + name: Fees + order: + "$serde_json::private::Number": "4" + output: + fee: + broker: + "$serde_json::private::Number": "45" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: {} + rule: + _id: 4b4e7a3c-17f9-451b-9099-d938de7bfbbb + 453ed4ec-8754-4768-823a-0741e12926ee: + id: 453ed4ec-8754-4768-823a-0741e12926ee + input: + base: + pi: + "$serde_json::private::Number": "75" + pl: + "$serde_json::private::Number": "50" + fee: + broker: + "$serde_json::private::Number": "45" + tax: + gst: + "$serde_json::private::Number": "10" + name: Aggregator + order: + "$serde_json::private::Number": "5" + output: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "125" + - key: gst + title: GST + value: + "$serde_json::private::Number": "17" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "45" + performance: "[perf]" + traceData: + log: [] + 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6: + id: 4b197c9b-8db6-4d67-8e64-2ea7d262b1c6 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + country: CA + coverage: + pi: 2M + pl: 20M + performance: "[perf]" + traceData: ~ + 52d501fa-5089-471a-81e1-9d604b6b864d: + id: 52d501fa-5089-471a-81e1-9d604b6b864d + input: + breakdown: + - key: premium + title: Premium + value: + "$serde_json::private::Number": "125" + - key: gst + title: GST + value: + "$serde_json::private::Number": "17" + - key: brokerFee + title: Broker Fee + value: + "$serde_json::private::Number": "45" + name: Response + order: + "$serde_json::private::Number": "6" + output: ~ + performance: "[perf]" + traceData: ~ + 831e22b5-93c4-4963-9d21-8af157dd1606: + id: 831e22b5-93c4-4963-9d21-8af157dd1606 + input: + country: CA + coverage: + pi: 2M + pl: 20M + name: PL Base + order: + "$serde_json::private::Number": "1" + output: + base: + pl: + "$serde_json::private::Number": "50" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + coverage.pl: 20M + rule: + _id: 5a8986b1-27a3-4961-ab6d-e32fb773e083 + "coverage.pl[6d179b45-a0b7-4c85-8324-73058f3def42]": "\"20M\"" + b9d38a6e-2d57-483c-9765-66d97b940a04: + id: b9d38a6e-2d57-483c-9765-66d97b940a04 + input: + country: CA + coverage: + pi: 2M + pl: 20M + name: GST + order: + "$serde_json::private::Number": "2" + output: + tax: + gst: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + country: CA + state: ~ + rule: + _id: 35babb81-b350-4445-853f-3877892910f9 + "country[5ca5e8d1-8339-483b-9c81-cdd34a4fb953]": "\"CA\"" + "state[8342de09-7a13-4d3b-82f9-156e2381817d]": "" + ebec39cc-ac87-4145-ae5d-744759a37268: + id: ebec39cc-ac87-4145-ae5d-744759a37268 + input: + country: CA + coverage: + pi: 2M + pl: 20M + name: PI Base + order: + "$serde_json::private::Number": "3" + output: + base: + pi: + "$serde_json::private::Number": "75" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + coverage.pi: 2M + rule: + _id: 9b10a56d-ee99-40f3-aa30-85ed38f60ec7 + "coverage.pi[ec711970-6b90-492f-8b5b-4a6e7cbf3088]": "\"2M\"" diff --git a/core/engine/tests/snapshots/engine__insurance-coverage-calculator_0.snap b/core/engine/tests/snapshots/engine__insurance-coverage-calculator_0.snap new file mode 100644 index 00000000..70f6a398 --- /dev/null +++ b/core/engine/tests/snapshots/engine__insurance-coverage-calculator_0.snap @@ -0,0 +1,255 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + additionalCoverageRecommendations: + - additionalCoverage: + amount: + "$serde_json::private::Number": "0" + recommended: false + level: medium + type: flood + - additionalCoverage: + amount: + "$serde_json::private::Number": "0" + recommended: false + level: low + type: earthquake + additionalRisks: + - level: medium + type: flood + - level: low + type: earthquake + basePackage: basic + customerData: + preferredDeductible: + "$serde_json::private::Number": "1500" + propertyAge: + "$serde_json::private::Number": "15" + propertyType: single-family + propertyValue: + "$serde_json::private::Number": "450000" + riskAssessment: + areaRiskLevel: medium + claimHistory: + pastClaims: + "$serde_json::private::Number": "1" + severityLevel: low +trace: + dt1: + id: dt1 + input: + additionalRisks: + - level: medium + type: flood + - level: low + type: earthquake + customerData: + preferredDeductible: + "$serde_json::private::Number": "1500" + propertyAge: + "$serde_json::private::Number": "15" + propertyType: single-family + propertyValue: + "$serde_json::private::Number": "450000" + riskAssessment: + areaRiskLevel: medium + claimHistory: + pastClaims: + "$serde_json::private::Number": "1" + severityLevel: low + name: determineBasePackage + order: + "$serde_json::private::Number": "1" + output: + additionalRisks: + - level: medium + type: flood + - level: low + type: earthquake + basePackage: basic + customerData: + preferredDeductible: + "$serde_json::private::Number": "1500" + propertyAge: + "$serde_json::private::Number": "15" + propertyType: single-family + propertyValue: + "$serde_json::private::Number": "450000" + riskAssessment: + areaRiskLevel: medium + claimHistory: + pastClaims: + "$serde_json::private::Number": "1" + severityLevel: low + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + customerData.propertyValue: + "$serde_json::private::Number": "450000" + riskAssessment.areaRiskLevel: medium + rule: + _id: r1-4 + "customerData.propertyValue[i1-1]": ">= 300000" + "riskAssessment.areaRiskLevel[i1-2]": "'medium'" + dt2: + id: dt2 + input: + additionalRisks: + - level: medium + type: flood + - level: low + type: earthquake + basePackage: basic + customerData: + preferredDeductible: + "$serde_json::private::Number": "1500" + propertyAge: + "$serde_json::private::Number": "15" + propertyType: single-family + propertyValue: + "$serde_json::private::Number": "450000" + riskAssessment: + areaRiskLevel: medium + claimHistory: + pastClaims: + "$serde_json::private::Number": "1" + severityLevel: low + name: calculateCoverageLevels + order: + "$serde_json::private::Number": "2" + output: + additionalRisks: + - level: medium + type: flood + - level: low + type: earthquake + basePackage: basic + customerData: + preferredDeductible: + "$serde_json::private::Number": "1500" + propertyAge: + "$serde_json::private::Number": "15" + propertyType: single-family + propertyValue: + "$serde_json::private::Number": "450000" + riskAssessment: + areaRiskLevel: medium + claimHistory: + pastClaims: + "$serde_json::private::Number": "1" + severityLevel: low + performance: "[perf]" + traceData: ~ + dt3: + id: dt3 + input: + additionalRisks: + - level: medium + type: flood + - level: low + type: earthquake + basePackage: basic + customerData: + preferredDeductible: + "$serde_json::private::Number": "1500" + propertyAge: + "$serde_json::private::Number": "15" + propertyType: single-family + propertyValue: + "$serde_json::private::Number": "450000" + riskAssessment: + areaRiskLevel: medium + claimHistory: + pastClaims: + "$serde_json::private::Number": "1" + severityLevel: low + name: additionalCoverageRecommendations + order: + "$serde_json::private::Number": "3" + output: + additionalCoverageRecommendations: + - additionalCoverage: + amount: + "$serde_json::private::Number": "0" + recommended: false + level: medium + type: flood + - additionalCoverage: + amount: + "$serde_json::private::Number": "0" + recommended: false + level: low + type: earthquake + additionalRisks: + - level: medium + type: flood + - level: low + type: earthquake + basePackage: basic + customerData: + preferredDeductible: + "$serde_json::private::Number": "1500" + propertyAge: + "$serde_json::private::Number": "15" + propertyType: single-family + propertyValue: + "$serde_json::private::Number": "450000" + riskAssessment: + areaRiskLevel: medium + claimHistory: + pastClaims: + "$serde_json::private::Number": "1" + severityLevel: low + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "6" + reference_map: + additionalRisks.level: ~ + additionalRisks.type: ~ + rule: + _id: r3-7 + "additionalRisks.level[i3-2]": "" + "additionalRisks.type[i3-1]": "" + - index: + "$serde_json::private::Number": "6" + reference_map: + additionalRisks.level: ~ + additionalRisks.type: ~ + rule: + _id: r3-7 + "additionalRisks.level[i3-2]": "" + "additionalRisks.type[i3-1]": "" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + additionalRisks: + - level: medium + type: flood + - level: low + type: earthquake + customerData: + preferredDeductible: + "$serde_json::private::Number": "1500" + propertyAge: + "$serde_json::private::Number": "15" + propertyType: single-family + propertyValue: + "$serde_json::private::Number": "450000" + riskAssessment: + areaRiskLevel: medium + claimHistory: + pastClaims: + "$serde_json::private::Number": "1" + severityLevel: low + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__insurance-prior-authorization_0.snap b/core/engine/tests/snapshots/engine__insurance-prior-authorization_0.snap new file mode 100644 index 00000000..b976042f --- /dev/null +++ b/core/engine/tests/snapshots/engine__insurance-prior-authorization_0.snap @@ -0,0 +1,180 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + reason: Advanced imaging requires prior authorization + requiresAuthorization: true + timestamp: + "$serde_json::private::Number": "1755682995" +trace: + commercialRules: + id: commercialRules + input: + diagnosisCodes: + - M54.5 + - M51.26 + patientInfo: + insuranceType: Commercial + serviceDetails: + code: "70551" + cost: + "$serde_json::private::Number": "1200" + isEmergency: false + serviceType: Imaging + name: Commercial Rules + order: + "$serde_json::private::Number": "2" + output: + authorizationReason: Advanced imaging requires prior authorization + diagnosisCodes: + - M54.5 + - M51.26 + patientInfo: + insuranceType: Commercial + requiresAuthorization: true + serviceDetails: + code: "70551" + cost: + "$serde_json::private::Number": "1200" + isEmergency: false + serviceType: Imaging + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + serviceType: Imaging + rule: + _id: r3 + "serviceType[i1]": "'Imaging'" + diagnosisCheck: + id: diagnosisCheck + input: + authorizationReason: Advanced imaging requires prior authorization + diagnosisCodes: + - M54.5 + - M51.26 + patientInfo: + insuranceType: Commercial + requiresAuthorization: true + serviceDetails: + code: "70551" + cost: + "$serde_json::private::Number": "1200" + isEmergency: false + serviceType: Imaging + name: Diagnosis Code Exclusions + order: + "$serde_json::private::Number": "3" + output: + authorizationReason: Advanced imaging requires prior authorization + diagnosisCodes: + - M54.5 + - M51.26 + patientInfo: + insuranceType: Commercial + requiresAuthorization: true + serviceDetails: + code: "70551" + cost: + "$serde_json::private::Number": "1200" + isEmergency: false + serviceType: Imaging + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + diagnosisCodes: + - M54.5 + - M51.26 + rule: + _id: r4 + "diagnosisCodes[i1]": "" + finalDetermination: + id: finalDetermination + input: + authorizationReason: Advanced imaging requires prior authorization + diagnosisCodes: + - M54.5 + - M51.26 + patientInfo: + insuranceType: Commercial + requiresAuthorization: true + serviceDetails: + code: "70551" + cost: + "$serde_json::private::Number": "1200" + isEmergency: false + serviceType: Imaging + name: Final Determination + order: + "$serde_json::private::Number": "4" + output: + reason: Advanced imaging requires prior authorization + requiresAuthorization: true + timestamp: + "$serde_json::private::Number": "1755682995" + performance: "[perf]" + traceData: + reason: + result: "\"Advanced imaging requires prior authorization\"" + requiresAuthorization: + result: "true" + timestamp: + result: "1755682995" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + diagnosisCodes: + - M54.5 + - M51.26 + patientInfo: + insuranceType: Commercial + serviceDetails: + code: "70551" + cost: + "$serde_json::private::Number": "1200" + isEmergency: false + serviceType: Imaging + performance: "[perf]" + traceData: ~ + insuranceTypeCheck: + id: insuranceTypeCheck + input: + diagnosisCodes: + - M54.5 + - M51.26 + patientInfo: + insuranceType: Commercial + serviceDetails: + code: "70551" + cost: + "$serde_json::private::Number": "1200" + isEmergency: false + serviceType: Imaging + name: Insurance Type Check + order: + "$serde_json::private::Number": "1" + output: + diagnosisCodes: + - M54.5 + - M51.26 + patientInfo: + insuranceType: Commercial + serviceDetails: + code: "70551" + cost: + "$serde_json::private::Number": "1200" + isEmergency: false + serviceType: Imaging + performance: "[perf]" + traceData: + statements: + - id: s3 diff --git a/core/engine/tests/snapshots/engine__insurance-underwriting-risk_0.snap b/core/engine/tests/snapshots/engine__insurance-underwriting-risk_0.snap new file mode 100644 index 00000000..6338d23b --- /dev/null +++ b/core/engine/tests/snapshots/engine__insurance-underwriting-risk_0.snap @@ -0,0 +1,276 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + answers: + age: + "$serde_json::private::Number": "58" + coverageAmount: + "$serde_json::private::Number": "1200000" + hasForeignResidency: false + hasHighRiskMedicalCondition: true + hasIncompleteInformation: false + hasInformationDiscrepancy: true + hazardousOccupation: false + multiplePreExistingConditions: true + recentHospitalization: false + applicantName: Jane Smith + applicationId: APP-12345 + riskDescriptions: + - High risk medical condition + - Multiple pre-existing conditions + riskFactors: + - description: High risk medical condition + points: + "$serde_json::private::Number": "10" + - description: Multiple pre-existing conditions + points: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "30" + underwriting: + needsManualReview: false + referralReason: No referral required +trace: + dt1: + id: dt1 + input: + answers: + age: + "$serde_json::private::Number": "58" + coverageAmount: + "$serde_json::private::Number": "1200000" + hasForeignResidency: false + hasHighRiskMedicalCondition: true + hasIncompleteInformation: false + hasInformationDiscrepancy: true + hazardousOccupation: false + multiplePreExistingConditions: true + recentHospitalization: false + applicantName: Jane Smith + applicationId: APP-12345 + name: risk_factors + order: + "$serde_json::private::Number": "1" + output: + answers: + age: + "$serde_json::private::Number": "58" + coverageAmount: + "$serde_json::private::Number": "1200000" + hasForeignResidency: false + hasHighRiskMedicalCondition: true + hasIncompleteInformation: false + hasInformationDiscrepancy: true + hazardousOccupation: false + multiplePreExistingConditions: true + recentHospitalization: false + applicantName: Jane Smith + applicationId: APP-12345 + riskFactors: + - description: High risk medical condition + points: + "$serde_json::private::Number": "10" + - description: Multiple pre-existing conditions + points: + "$serde_json::private::Number": "20" + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: + answers.age: + "$serde_json::private::Number": "58" + answers.hasHighRiskMedicalCondition: true + answers.hazardousOccupation: false + answers.multiplePreExistingConditions: true + answers.recentHospitalization: false + rule: + _id: r1-1 + "answers.age[i1-5]": "" + "answers.hasHighRiskMedicalCondition[i1-1]": "true" + "answers.hazardousOccupation[i1-4]": "" + "answers.multiplePreExistingConditions[i1-3]": "" + "answers.recentHospitalization[i1-2]": "" + - index: + "$serde_json::private::Number": "2" + reference_map: + answers.age: + "$serde_json::private::Number": "58" + answers.hasHighRiskMedicalCondition: true + answers.hazardousOccupation: false + answers.multiplePreExistingConditions: true + answers.recentHospitalization: false + rule: + _id: r1-3 + "answers.age[i1-5]": "" + "answers.hasHighRiskMedicalCondition[i1-1]": "" + "answers.hazardousOccupation[i1-4]": "" + "answers.multiplePreExistingConditions[i1-3]": "true" + "answers.recentHospitalization[i1-2]": "" + dt2: + id: dt2 + input: + answers: + age: + "$serde_json::private::Number": "58" + coverageAmount: + "$serde_json::private::Number": "1200000" + hasForeignResidency: false + hasHighRiskMedicalCondition: true + hasIncompleteInformation: false + hasInformationDiscrepancy: true + hazardousOccupation: false + multiplePreExistingConditions: true + recentHospitalization: false + applicantName: Jane Smith + applicationId: APP-12345 + riskDescriptions: + - High risk medical condition + - Multiple pre-existing conditions + riskFactors: + - description: High risk medical condition + points: + "$serde_json::private::Number": "10" + - description: Multiple pre-existing conditions + points: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "30" + name: referral_decision + order: + "$serde_json::private::Number": "3" + output: + answers: + age: + "$serde_json::private::Number": "58" + coverageAmount: + "$serde_json::private::Number": "1200000" + hasForeignResidency: false + hasHighRiskMedicalCondition: true + hasIncompleteInformation: false + hasInformationDiscrepancy: true + hazardousOccupation: false + multiplePreExistingConditions: true + recentHospitalization: false + applicantName: Jane Smith + applicationId: APP-12345 + riskDescriptions: + - High risk medical condition + - Multiple pre-existing conditions + riskFactors: + - description: High risk medical condition + points: + "$serde_json::private::Number": "10" + - description: Multiple pre-existing conditions + points: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "30" + underwriting: + needsManualReview: false + referralReason: No referral required + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "5" + reference_map: + answers.coverageAmount: + "$serde_json::private::Number": "1200000" + answers.hasForeignResidency: false + answers.hasIncompleteInformation: false + answers.hasInformationDiscrepancy: true + totalRiskScore: + "$serde_json::private::Number": "30" + rule: + _id: r2-6 + "answers.coverageAmount[i2-1]": "" + "answers.hasForeignResidency[i2-5]": "" + "answers.hasIncompleteInformation[i2-3]": "" + "answers.hasInformationDiscrepancy[i2-4]": "" + "totalRiskScore[i2-2]": "" + ex1: + id: ex1 + input: + answers: + age: + "$serde_json::private::Number": "58" + coverageAmount: + "$serde_json::private::Number": "1200000" + hasForeignResidency: false + hasHighRiskMedicalCondition: true + hasIncompleteInformation: false + hasInformationDiscrepancy: true + hazardousOccupation: false + multiplePreExistingConditions: true + recentHospitalization: false + applicantName: Jane Smith + applicationId: APP-12345 + riskFactors: + - description: High risk medical condition + points: + "$serde_json::private::Number": "10" + - description: Multiple pre-existing conditions + points: + "$serde_json::private::Number": "20" + name: calculate_risk_score + order: + "$serde_json::private::Number": "2" + output: + answers: + age: + "$serde_json::private::Number": "58" + coverageAmount: + "$serde_json::private::Number": "1200000" + hasForeignResidency: false + hasHighRiskMedicalCondition: true + hasIncompleteInformation: false + hasInformationDiscrepancy: true + hazardousOccupation: false + multiplePreExistingConditions: true + recentHospitalization: false + applicantName: Jane Smith + applicationId: APP-12345 + riskDescriptions: + - High risk medical condition + - Multiple pre-existing conditions + riskFactors: + - description: High risk medical condition + points: + "$serde_json::private::Number": "10" + - description: Multiple pre-existing conditions + points: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "30" + performance: "[perf]" + traceData: + riskDescriptions: + result: "[\"High risk medical condition\",\"Multiple pre-existing conditions\"]" + totalRiskScore: + result: "30" + ip1: + id: ip1 + input: ~ + name: application + order: + "$serde_json::private::Number": "0" + output: + answers: + age: + "$serde_json::private::Number": "58" + coverageAmount: + "$serde_json::private::Number": "1200000" + hasForeignResidency: false + hasHighRiskMedicalCondition: true + hasIncompleteInformation: false + hasInformationDiscrepancy: true + hazardousOccupation: false + multiplePreExistingConditions: true + recentHospitalization: false + applicantName: Jane Smith + applicationId: APP-12345 + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__international-roaming-policy-manager_0.snap b/core/engine/tests/snapshots/engine__international-roaming-policy-manager_0.snap new file mode 100644 index 00000000..4bce3907 --- /dev/null +++ b/core/engine/tests/snapshots/engine__international-roaming-policy-manager_0.snap @@ -0,0 +1,183 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + isDataRoamingEnabled: true + isVoiceRoamingEnabled: true + remainingDataAllowance: + "$serde_json::private::Number": "3750" + totalEstimatedDailyCost: + "$serde_json::private::Number": "252.75" +trace: + dt1: + id: dt1 + input: + customer: + id: C123456789 + profile: + avgDailyDataUsage: + "$serde_json::private::Number": "250" + avgDailySmsUsage: + "$serde_json::private::Number": "10" + avgDailyVoiceUsage: + "$serde_json::private::Number": "15" + dataRoamingQuota: + "$serde_json::private::Number": "5000" + isDataRoamingAllowed: true + isVoiceRoamingAllowed: true + planType: International Plus + usage: + dataRoamingUsed: + "$serde_json::private::Number": "1250" + smsRoamingUsed: + "$serde_json::private::Number": "22" + voiceRoamingUsed: + "$serde_json::private::Number": "45" + destination: + arrivalDate: 2025-03-20 + country: France + departureDate: 2025-03-27 + region: EU + name: roamingPolicyLookup + order: + "$serde_json::private::Number": "1" + output: + customer: + id: C123456789 + profile: + avgDailyDataUsage: + "$serde_json::private::Number": "250" + avgDailySmsUsage: + "$serde_json::private::Number": "10" + avgDailyVoiceUsage: + "$serde_json::private::Number": "15" + dataRoamingQuota: + "$serde_json::private::Number": "5000" + isDataRoamingAllowed: true + isVoiceRoamingAllowed: true + planType: International Plus + usage: + dataRoamingUsed: + "$serde_json::private::Number": "1250" + smsRoamingUsed: + "$serde_json::private::Number": "22" + voiceRoamingUsed: + "$serde_json::private::Number": "45" + destination: + arrivalDate: 2025-03-20 + country: France + departureDate: 2025-03-27 + region: EU + policy: + dataAccess: full + dataRate: + "$serde_json::private::Number": "1" + serviceTier: premium + smsRate: + "$serde_json::private::Number": "0.05" + voiceRate: + "$serde_json::private::Number": "0.15" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + destination.region: EU + rule: + _id: r1-1 + "destination.region[i1-1]": "'EU'" + ex1: + id: ex1 + input: + customer: + id: C123456789 + profile: + avgDailyDataUsage: + "$serde_json::private::Number": "250" + avgDailySmsUsage: + "$serde_json::private::Number": "10" + avgDailyVoiceUsage: + "$serde_json::private::Number": "15" + dataRoamingQuota: + "$serde_json::private::Number": "5000" + isDataRoamingAllowed: true + isVoiceRoamingAllowed: true + planType: International Plus + usage: + dataRoamingUsed: + "$serde_json::private::Number": "1250" + smsRoamingUsed: + "$serde_json::private::Number": "22" + voiceRoamingUsed: + "$serde_json::private::Number": "45" + destination: + arrivalDate: 2025-03-20 + country: France + departureDate: 2025-03-27 + region: EU + policy: + dataAccess: full + dataRate: + "$serde_json::private::Number": "1" + serviceTier: premium + smsRate: + "$serde_json::private::Number": "0.05" + voiceRate: + "$serde_json::private::Number": "0.15" + name: calculateRoamingParameters + order: + "$serde_json::private::Number": "2" + output: + isDataRoamingEnabled: true + isVoiceRoamingEnabled: true + remainingDataAllowance: + "$serde_json::private::Number": "3750" + totalEstimatedDailyCost: + "$serde_json::private::Number": "252.75" + performance: "[perf]" + traceData: + isDataRoamingEnabled: + result: "true" + isVoiceRoamingEnabled: + result: "true" + remainingDataAllowance: + result: "3750" + totalEstimatedDailyCost: + result: "252.75" + ip1: + id: ip1 + input: ~ + name: roamingRequest + order: + "$serde_json::private::Number": "0" + output: + customer: + id: C123456789 + profile: + avgDailyDataUsage: + "$serde_json::private::Number": "250" + avgDailySmsUsage: + "$serde_json::private::Number": "10" + avgDailyVoiceUsage: + "$serde_json::private::Number": "15" + dataRoamingQuota: + "$serde_json::private::Number": "5000" + isDataRoamingAllowed: true + isVoiceRoamingAllowed: true + planType: International Plus + usage: + dataRoamingUsed: + "$serde_json::private::Number": "1250" + smsRoamingUsed: + "$serde_json::private::Number": "22" + voiceRoamingUsed: + "$serde_json::private::Number": "45" + destination: + arrivalDate: 2025-03-20 + country: France + departureDate: 2025-03-27 + region: EU + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__last-mile-delivery-assignment_0.snap b/core/engine/tests/snapshots/engine__last-mile-delivery-assignment_0.snap new file mode 100644 index 00000000..539487be --- /dev/null +++ b/core/engine/tests/snapshots/engine__last-mile-delivery-assignment_0.snap @@ -0,0 +1,561 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + assignmentDetails: + assignmentScore: + "$serde_json::private::Number": "28" + deliveryPersonId: DP-789 + estimatedArrival: + "$serde_json::private::Number": "1755683930" + packageId: PKG-12345 + assignmentStatus: assigned + capacityFactor: + "$serde_json::private::Number": "5" + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + distanceScore: + "$serde_json::private::Number": "7" + matchScore: + "$serde_json::private::Number": "10" + message: Package successfully assigned to delivery person + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + priorityLevel: high + recommendedAssignment: true + slaFactor: + "$serde_json::private::Number": "6" + totalScore: + "$serde_json::private::Number": "28" +trace: + dt1: + id: dt1 + input: + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + name: calculate_match_score + order: + "$serde_json::private::Number": "1" + output: + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + matchScore: + "$serde_json::private::Number": "10" + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + priorityLevel: high + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: r1-1 + ex1: + id: ex1 + input: + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + matchScore: + "$serde_json::private::Number": "10" + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + priorityLevel: high + name: calculate_final_score + order: + "$serde_json::private::Number": "2" + output: + capacityFactor: + "$serde_json::private::Number": "5" + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + distanceScore: + "$serde_json::private::Number": "7" + matchScore: + "$serde_json::private::Number": "10" + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + priorityLevel: high + recommendedAssignment: true + slaFactor: + "$serde_json::private::Number": "6" + totalScore: + "$serde_json::private::Number": "28" + performance: "[perf]" + traceData: + capacityFactor: + result: "5" + distanceScore: + result: "7" + recommendedAssignment: + result: "true" + slaFactor: + result: "6" + totalScore: + result: "28" + ex2: + id: ex2 + input: + capacityFactor: + "$serde_json::private::Number": "5" + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + distanceScore: + "$serde_json::private::Number": "7" + matchScore: + "$serde_json::private::Number": "10" + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + priorityLevel: high + recommendedAssignment: true + slaFactor: + "$serde_json::private::Number": "6" + totalScore: + "$serde_json::private::Number": "28" + name: create_assignment + order: + "$serde_json::private::Number": "4" + output: + assignmentDetails: + assignmentScore: + "$serde_json::private::Number": "28" + deliveryPersonId: DP-789 + estimatedArrival: + "$serde_json::private::Number": "1755683930" + packageId: PKG-12345 + assignmentStatus: assigned + capacityFactor: + "$serde_json::private::Number": "5" + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + distanceScore: + "$serde_json::private::Number": "7" + matchScore: + "$serde_json::private::Number": "10" + message: Package successfully assigned to delivery person + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + priorityLevel: high + recommendedAssignment: true + slaFactor: + "$serde_json::private::Number": "6" + totalScore: + "$serde_json::private::Number": "28" + performance: "[perf]" + traceData: + assignmentDetails: + result: "{\"deliveryPersonId\":\"DP-789\",\"assignmentScore\":28,\"packageId\":\"PKG-12345\",\"estimatedArrival\":1755683930}" + assignmentStatus: + result: "\"assigned\"" + message: + result: "\"Package successfully assigned to delivery person\"" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + performance: "[perf]" + traceData: ~ + sw1: + id: sw1 + input: + capacityFactor: + "$serde_json::private::Number": "5" + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + distanceScore: + "$serde_json::private::Number": "7" + matchScore: + "$serde_json::private::Number": "10" + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + priorityLevel: high + recommendedAssignment: true + slaFactor: + "$serde_json::private::Number": "6" + totalScore: + "$serde_json::private::Number": "28" + name: determine_assignment + order: + "$serde_json::private::Number": "3" + output: + capacityFactor: + "$serde_json::private::Number": "5" + deliveryPerson: + collectSignatureEquipped: true + currentLocation: + latitude: + "$serde_json::private::Number": "40.7128" + longitude: + "$serde_json::private::Number": "-74.006" + currentZone: downtown + id: DP-789 + name: Alex Johnson + remainingCapacity: + "$serde_json::private::Number": "50" + remainingDeliveries: + "$serde_json::private::Number": "8" + shiftEndsAt: "2025-03-19T20:00:00Z" + skills: + - express_certified + - heavy_lifting + - collectSignature + vehicleType: van + distanceScore: + "$serde_json::private::Number": "7" + matchScore: + "$serde_json::private::Number": "10" + package: + deliveryDeadline: "2025-03-19T16:00:00Z" + deliveryZone: downtown + dimensions: + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + width: + "$serde_json::private::Number": "30" + distanceFromDeliveryPerson: + "$serde_json::private::Number": "5.2" + fragile: false + id: PKG-12345 + needsSignature: true + priority: express + specialInstructions: Leave with doorman if recipient unavailable + weight: + "$serde_json::private::Number": "22.5" + priorityLevel: high + recommendedAssignment: true + slaFactor: + "$serde_json::private::Number": "6" + totalScore: + "$serde_json::private::Number": "28" + performance: "[perf]" + traceData: + statements: + - id: s1-1 diff --git a/core/engine/tests/snapshots/engine__legacy-plan-management_0.snap b/core/engine/tests/snapshots/engine__legacy-plan-management_0.snap new file mode 100644 index 00000000..28cc1a11 --- /dev/null +++ b/core/engine/tests/snapshots/engine__legacy-plan-management_0.snap @@ -0,0 +1,377 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + migrationEligible: false + migrationOfferDetails: Protected legacy plan - migration not recommended + recommendedPlanId: LEGACY-PLAN-2019 + simplifiedPlanName: Legacy Unlimited Family Plan +trace: + e2398550-dac8-4d1f-a720-e09291e34f2e: + id: e2398550-dac8-4d1f-a720-e09291e34f2e + input: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + migrationEligible: false + migrationOfferDetails: Protected legacy plan - migration not recommended + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + planDetails: + category: legacy + dataAllowanceGB: + "$serde_json::private::Number": "25" + description: This is a grandfathered legacy plan with protected benefits. + internationalMinutes: + "$serde_json::private::Number": "120" + isGrandfathered: true + retainSpecialFeatures: true + recommendedPlanId: LEGACY-PLAN-2019 + simplifiedPlanName: Legacy Unlimited Family Plan + name: omitFields + order: + "$serde_json::private::Number": "5" + output: + migrationEligible: false + migrationOfferDetails: Protected legacy plan - migration not recommended + recommendedPlanId: LEGACY-PLAN-2019 + simplifiedPlanName: Legacy Unlimited Family Plan + performance: "[perf]" + traceData: + customer: + result: "null" + plan: + result: "null" + planDetails: + result: "null" + migrationEligibility: + id: migrationEligibility + input: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + planDetails: + category: legacy + dataAllowanceGB: + "$serde_json::private::Number": "25" + description: This is a grandfathered legacy plan with protected benefits. + internationalMinutes: + "$serde_json::private::Number": "120" + isGrandfathered: true + retainSpecialFeatures: true + recommendedPlanId: LEGACY-PLAN-2019 + simplifiedPlanName: Legacy Unlimited Family Plan + name: determineMigrationEligibility + order: + "$serde_json::private::Number": "4" + output: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + migrationEligible: false + migrationOfferDetails: Protected legacy plan - migration not recommended + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + planDetails: + category: legacy + dataAllowanceGB: + "$serde_json::private::Number": "25" + description: This is a grandfathered legacy plan with protected benefits. + internationalMinutes: + "$serde_json::private::Number": "120" + isGrandfathered: true + retainSpecialFeatures: true + recommendedPlanId: LEGACY-PLAN-2019 + simplifiedPlanName: Legacy Unlimited Family Plan + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + planDetails.category: legacy + planDetails.isGrandfathered: true + rule: + _id: migrationRule1 + "planDetails.category[category]": "'legacy'" + "planDetails.isGrandfathered[grandfathered]": "true" + planBenefits: + id: planBenefits + input: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + planDetails: + category: legacy + isGrandfathered: true + name: determineBenefits + order: + "$serde_json::private::Number": "2" + output: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + planDetails: + category: legacy + dataAllowanceGB: + "$serde_json::private::Number": "25" + description: This is a grandfathered legacy plan with protected benefits. + internationalMinutes: + "$serde_json::private::Number": "120" + isGrandfathered: true + retainSpecialFeatures: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + planDetails.category: legacy + planDetails.isGrandfathered: true + rule: + _id: benefitRule1 + "planDetails.category[planCategory]": "'legacy'" + "planDetails.isGrandfathered[isGrandfathered]": "true" + planIdentifier: + id: planIdentifier + input: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + name: identifyPlanType + order: + "$serde_json::private::Number": "1" + output: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + planDetails: + category: legacy + isGrandfathered: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + customer.tenureInMonths: + "$serde_json::private::Number": "36" + plan.ageInMonths: + "$serde_json::private::Number": "48" + plan.name: Legacy Unlimited Family Plan + rule: + _id: rule1 + "customer.tenureInMonths[customerTenure]": "> 24" + "plan.ageInMonths[planAge]": "> 36" + "plan.name[planName]": "contains($, \"Legacy\")" + planMapping: + id: planMapping + input: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + planDetails: + category: legacy + dataAllowanceGB: + "$serde_json::private::Number": "25" + description: This is a grandfathered legacy plan with protected benefits. + internationalMinutes: + "$serde_json::private::Number": "120" + isGrandfathered: true + retainSpecialFeatures: true + name: mapToCurrentCatalog + order: + "$serde_json::private::Number": "3" + output: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + planDetails: + category: legacy + dataAllowanceGB: + "$serde_json::private::Number": "25" + description: This is a grandfathered legacy plan with protected benefits. + internationalMinutes: + "$serde_json::private::Number": "120" + isGrandfathered: true + retainSpecialFeatures: true + recommendedPlanId: LEGACY-PLAN-2019 + simplifiedPlanName: Legacy Unlimited Family Plan + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + planDetails.category: legacy + planDetails.isGrandfathered: true + rule: + _id: mappingRule1 + "planDetails.category[category]": "'legacy'" + "planDetails.isGrandfathered[grandfathered]": "true" + requestNode: + id: requestNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + id: CUST-12345 + location: Urban + segment: Family + tenureInMonths: + "$serde_json::private::Number": "36" + plan: + ageInMonths: + "$serde_json::private::Number": "48" + dataAllowance: + "$serde_json::private::Number": "25" + features: + - Unlimited SMS + - Free Evening Calls + - Family Sharing + id: LEGACY-PLAN-2019 + internationalMinutes: + "$serde_json::private::Number": "120" + name: Legacy Unlimited Family Plan + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__loan-approval_0.snap b/core/engine/tests/snapshots/engine__loan-approval_0.snap new file mode 100644 index 00000000..340cd848 --- /dev/null +++ b/core/engine/tests/snapshots/engine__loan-approval_0.snap @@ -0,0 +1,460 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + approval: true + baseRate: + "$serde_json::private::Number": "5.5" + interestRate: + "$serde_json::private::Number": "6.5" + riskAdjustment: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "80" +trace: + calculateDTI: + id: calculateDTI + input: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + name: debtToIncomeRatio + order: + "$serde_json::private::Number": "3" + output: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + dtiRatio: + "$serde_json::private::Number": "30" + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + performance: "[perf]" + traceData: + dtiRatio: + result: "30" + calculateInterestRate: + id: calculateInterestRate + input: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + dtiRatio: + "$serde_json::private::Number": "30" + employmentPoints: + "$serde_json::private::Number": "15" + employmentStability: stable + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + rejectionReasons: [] + name: interestRateCalculation + order: + "$serde_json::private::Number": "7" + output: + approval: true + baseRate: + "$serde_json::private::Number": "5.5" + interestRate: + "$serde_json::private::Number": "6.5" + riskAdjustment: + "$serde_json::private::Number": "20" + totalRiskScore: + "$serde_json::private::Number": "80" + performance: "[perf]" + traceData: + approval: + result: "true" + baseRate: + result: "5.5" + interestRate: + result: "6.5" + riskAdjustment: + result: "20" + totalRiskScore: + result: "80" + determineApproval: + id: determineApproval + input: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + dtiRatio: + "$serde_json::private::Number": "30" + employmentPoints: + "$serde_json::private::Number": "15" + employmentStability: stable + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + rejectionReasons: [] + name: loanApprovalDecision + order: + "$serde_json::private::Number": "6" + output: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + dtiRatio: + "$serde_json::private::Number": "30" + employmentPoints: + "$serde_json::private::Number": "15" + employmentStability: stable + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + rejectionReasons: [] + performance: "[perf]" + traceData: + statements: + - id: approval1 + evaluateCreditScore: + id: evaluateCreditScore + input: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditScore: + "$serde_json::private::Number": "685" + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + name: creditScoreEvaluation + order: + "$serde_json::private::Number": "1" + output: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + creditScore: + "$serde_json::private::Number": "685" + rule: + _id: cs3 + "creditScore[i1-1]": "[650..699]" + evaluateEmployment: + id: evaluateEmployment + input: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + dtiRatio: + "$serde_json::private::Number": "30" + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + name: employmentHistory + order: + "$serde_json::private::Number": "4" + output: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + dtiRatio: + "$serde_json::private::Number": "30" + employmentPoints: + "$serde_json::private::Number": "15" + employmentStability: stable + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: eh2 + evaluateIncome: + id: evaluateIncome + input: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + name: incomeVerification + order: + "$serde_json::private::Number": "2" + output: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + annualIncome: + "$serde_json::private::Number": "72000" + rule: + _id: iv2 + "annualIncome[i2-1]": "[60000..99999]" + input: + id: input + input: ~ + name: loanApplication + order: + "$serde_json::private::Number": "0" + output: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditScore: + "$serde_json::private::Number": "685" + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + performance: "[perf]" + traceData: ~ + rejectionReason: + id: rejectionReason + input: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + dtiRatio: + "$serde_json::private::Number": "30" + employmentPoints: + "$serde_json::private::Number": "15" + employmentStability: stable + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + name: determineLoanRejectionReason + order: + "$serde_json::private::Number": "5" + output: + annualIncome: + "$serde_json::private::Number": "72000" + applicantId: APL-12345 + creditRating: fair + creditScore: + "$serde_json::private::Number": "685" + creditScorePoints: + "$serde_json::private::Number": "15" + dtiRatio: + "$serde_json::private::Number": "30" + employmentPoints: + "$serde_json::private::Number": "15" + employmentStability: stable + employmentStatus: full_time + employmentYears: + "$serde_json::private::Number": "4" + incomeLevel: medium + incomePoints: + "$serde_json::private::Number": "20" + loanAmount: + "$serde_json::private::Number": "250000" + loanTerm: + "$serde_json::private::Number": "30" + monthlyDebt: + "$serde_json::private::Number": "1800" + monthlyIncome: + "$serde_json::private::Number": "6000" + rejectionReasons: [] + performance: "[perf]" + traceData: [] diff --git a/core/engine/tests/snapshots/engine__marketplace-listing-verification-system_0.snap b/core/engine/tests/snapshots/engine__marketplace-listing-verification-system_0.snap new file mode 100644 index 00000000..6bb0c09f --- /dev/null +++ b/core/engine/tests/snapshots/engine__marketplace-listing-verification-system_0.snap @@ -0,0 +1,361 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + category: + averagePrice: + "$serde_json::private::Number": "1500" + highValueBrands: + - LuxuryBrand + - PremiumDesigner + - ExclusiveFashion + id: CAT789 + name: Designer Handbags + type: luxury + hasLowRating: true + hasPreviousViolations: true + isHighValueBrand: true + isNewSeller: true + isSensitiveCategory: true + listing: + brand: LuxuryBrand + condition: New + description: "Authentic designer handbag, limited edition, comes with certificate" + id: LIST12345 + price: + "$serde_json::private::Number": "950" + title: Designer Handbag - Limited Edition + priceDeviationScore: + "$serde_json::private::Number": "36.66666666666666666666666667" + riskAssessment: + level: high + reason: Suspicious pricing for high-value brand with history of violations + seller: + accountAgeDays: + "$serde_json::private::Number": "45" + id: SELL456 + listingsCount: + "$serde_json::private::Number": "27" + name: FashionReseller + previousViolations: + "$serde_json::private::Number": "1" + rating: + "$serde_json::private::Number": "3.8" + verification: + message: High risk listing requires immediate manual verification + required: true + type: manual +trace: + calculateRiskFactors: + id: calculateRiskFactors + input: + category: + averagePrice: + "$serde_json::private::Number": "1500" + highValueBrands: + - LuxuryBrand + - PremiumDesigner + - ExclusiveFashion + id: CAT789 + name: Designer Handbags + type: luxury + listing: + brand: LuxuryBrand + condition: New + description: "Authentic designer handbag, limited edition, comes with certificate" + id: LIST12345 + price: + "$serde_json::private::Number": "950" + title: Designer Handbag - Limited Edition + seller: + accountAgeDays: + "$serde_json::private::Number": "45" + id: SELL456 + listingsCount: + "$serde_json::private::Number": "27" + name: FashionReseller + previousViolations: + "$serde_json::private::Number": "1" + rating: + "$serde_json::private::Number": "3.8" + name: calculateRiskFactors + order: + "$serde_json::private::Number": "1" + output: + category: + averagePrice: + "$serde_json::private::Number": "1500" + highValueBrands: + - LuxuryBrand + - PremiumDesigner + - ExclusiveFashion + id: CAT789 + name: Designer Handbags + type: luxury + hasLowRating: true + hasPreviousViolations: true + isHighValueBrand: true + isNewSeller: true + isSensitiveCategory: true + listing: + brand: LuxuryBrand + condition: New + description: "Authentic designer handbag, limited edition, comes with certificate" + id: LIST12345 + price: + "$serde_json::private::Number": "950" + title: Designer Handbag - Limited Edition + priceDeviationScore: + "$serde_json::private::Number": "36.66666666666666666666666667" + seller: + accountAgeDays: + "$serde_json::private::Number": "45" + id: SELL456 + listingsCount: + "$serde_json::private::Number": "27" + name: FashionReseller + previousViolations: + "$serde_json::private::Number": "1" + rating: + "$serde_json::private::Number": "3.8" + performance: "[perf]" + traceData: + hasLowRating: + result: "true" + hasPreviousViolations: + result: "true" + isHighValueBrand: + result: "true" + isNewSeller: + result: "true" + isSensitiveCategory: + result: "true" + priceDeviationScore: + result: "36.66666666666666666666666667" + determineAction: + id: determineAction + input: + category: + averagePrice: + "$serde_json::private::Number": "1500" + highValueBrands: + - LuxuryBrand + - PremiumDesigner + - ExclusiveFashion + id: CAT789 + name: Designer Handbags + type: luxury + hasLowRating: true + hasPreviousViolations: true + isHighValueBrand: true + isNewSeller: true + isSensitiveCategory: true + listing: + brand: LuxuryBrand + condition: New + description: "Authentic designer handbag, limited edition, comes with certificate" + id: LIST12345 + price: + "$serde_json::private::Number": "950" + title: Designer Handbag - Limited Edition + priceDeviationScore: + "$serde_json::private::Number": "36.66666666666666666666666667" + riskAssessment: + level: high + reason: Suspicious pricing for high-value brand with history of violations + seller: + accountAgeDays: + "$serde_json::private::Number": "45" + id: SELL456 + listingsCount: + "$serde_json::private::Number": "27" + name: FashionReseller + previousViolations: + "$serde_json::private::Number": "1" + rating: + "$serde_json::private::Number": "3.8" + name: determineAction + order: + "$serde_json::private::Number": "3" + output: + category: + averagePrice: + "$serde_json::private::Number": "1500" + highValueBrands: + - LuxuryBrand + - PremiumDesigner + - ExclusiveFashion + id: CAT789 + name: Designer Handbags + type: luxury + hasLowRating: true + hasPreviousViolations: true + isHighValueBrand: true + isNewSeller: true + isSensitiveCategory: true + listing: + brand: LuxuryBrand + condition: New + description: "Authentic designer handbag, limited edition, comes with certificate" + id: LIST12345 + price: + "$serde_json::private::Number": "950" + title: Designer Handbag - Limited Edition + priceDeviationScore: + "$serde_json::private::Number": "36.66666666666666666666666667" + riskAssessment: + level: high + reason: Suspicious pricing for high-value brand with history of violations + seller: + accountAgeDays: + "$serde_json::private::Number": "45" + id: SELL456 + listingsCount: + "$serde_json::private::Number": "27" + name: FashionReseller + previousViolations: + "$serde_json::private::Number": "1" + rating: + "$serde_json::private::Number": "3.8" + verification: + message: High risk listing requires immediate manual verification + required: true + type: manual + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + riskAssessment.level: high + rule: + _id: rule1 + "riskAssessment.level[i1]": "'high'" + evaluateRisk: + id: evaluateRisk + input: + category: + averagePrice: + "$serde_json::private::Number": "1500" + highValueBrands: + - LuxuryBrand + - PremiumDesigner + - ExclusiveFashion + id: CAT789 + name: Designer Handbags + type: luxury + hasLowRating: true + hasPreviousViolations: true + isHighValueBrand: true + isNewSeller: true + isSensitiveCategory: true + listing: + brand: LuxuryBrand + condition: New + description: "Authentic designer handbag, limited edition, comes with certificate" + id: LIST12345 + price: + "$serde_json::private::Number": "950" + title: Designer Handbag - Limited Edition + priceDeviationScore: + "$serde_json::private::Number": "36.66666666666666666666666667" + seller: + accountAgeDays: + "$serde_json::private::Number": "45" + id: SELL456 + listingsCount: + "$serde_json::private::Number": "27" + name: FashionReseller + previousViolations: + "$serde_json::private::Number": "1" + rating: + "$serde_json::private::Number": "3.8" + name: evaluateRiskLevel + order: + "$serde_json::private::Number": "2" + output: + category: + averagePrice: + "$serde_json::private::Number": "1500" + highValueBrands: + - LuxuryBrand + - PremiumDesigner + - ExclusiveFashion + id: CAT789 + name: Designer Handbags + type: luxury + hasLowRating: true + hasPreviousViolations: true + isHighValueBrand: true + isNewSeller: true + isSensitiveCategory: true + listing: + brand: LuxuryBrand + condition: New + description: "Authentic designer handbag, limited edition, comes with certificate" + id: LIST12345 + price: + "$serde_json::private::Number": "950" + title: Designer Handbag - Limited Edition + priceDeviationScore: + "$serde_json::private::Number": "36.66666666666666666666666667" + riskAssessment: + level: high + reason: Suspicious pricing for high-value brand with history of violations + seller: + accountAgeDays: + "$serde_json::private::Number": "45" + id: SELL456 + listingsCount: + "$serde_json::private::Number": "27" + name: FashionReseller + previousViolations: + "$serde_json::private::Number": "1" + rating: + "$serde_json::private::Number": "3.8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: rule1 + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + category: + averagePrice: + "$serde_json::private::Number": "1500" + highValueBrands: + - LuxuryBrand + - PremiumDesigner + - ExclusiveFashion + id: CAT789 + name: Designer Handbags + type: luxury + listing: + brand: LuxuryBrand + condition: New + description: "Authentic designer handbag, limited edition, comes with certificate" + id: LIST12345 + price: + "$serde_json::private::Number": "950" + title: Designer Handbag - Limited Edition + seller: + accountAgeDays: + "$serde_json::private::Number": "45" + id: SELL456 + listingsCount: + "$serde_json::private::Number": "27" + name: FashionReseller + previousViolations: + "$serde_json::private::Number": "1" + rating: + "$serde_json::private::Number": "3.8" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__marketplace-seller-grading-system_0.snap b/core/engine/tests/snapshots/engine__marketplace-seller-grading-system_0.snap new file mode 100644 index 00000000..06292120 --- /dev/null +++ b/core/engine/tests/snapshots/engine__marketplace-seller-grading-system_0.snap @@ -0,0 +1,343 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + grade: B + recommendedAction: Eligible for featured seller status + status: Good +trace: + dt1: + id: dt1 + input: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + name: evaluate_delivery + order: + "$serde_json::private::Number": "1" + output: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + scores: + delivery: + "$serde_json::private::Number": "4" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + metrics.onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + rule: + _id: r1-2 + "metrics.onTimeDeliveryRate[i1-1]": ">= 95" + dt2: + id: dt2 + input: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + name: evaluate_satisfaction + order: + "$serde_json::private::Number": "2" + output: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + scores: + customerSatisfaction: + "$serde_json::private::Number": "4" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + metrics.customerSatisfaction: + "$serde_json::private::Number": "4.7" + rule: + _id: r2-2 + "metrics.customerSatisfaction[i2-1]": ">= 4.5" + dt3: + id: dt3 + input: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + name: evaluate_inventory + order: + "$serde_json::private::Number": "3" + output: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + scores: + inventory: + "$serde_json::private::Number": "4" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + metrics.inventoryAccuracy: + "$serde_json::private::Number": "97.2" + rule: + _id: r3-2 + "metrics.inventoryAccuracy[i3-1]": ">= 95" + dt4: + id: dt4 + input: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + name: evaluate_compliance + order: + "$serde_json::private::Number": "4" + output: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + scores: + compliance: + "$serde_json::private::Number": "3" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + metrics.policyCompliance: + "$serde_json::private::Number": "94.8" + rule: + _id: r4-3 + "metrics.policyCompliance[i4-1]": ">= 90" + dt5: + id: dt5 + input: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + scores: + averageScore: + "$serde_json::private::Number": "3.75" + compliance: + "$serde_json::private::Number": "3" + customerSatisfaction: + "$serde_json::private::Number": "4" + delivery: + "$serde_json::private::Number": "4" + improvements: [] + inventory: + "$serde_json::private::Number": "4" + strengths: + - customerSatisfaction + - inventory + - delivery + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + name: calculate_final_grade + order: + "$serde_json::private::Number": "6" + output: + grade: B + recommendedAction: Eligible for featured seller status + status: Good + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + scores.averageScore: + "$serde_json::private::Number": "3.75" + rule: + _id: r5-2 + "scores.averageScore[i5-1]": ">= 3.5" + ex1: + id: ex1 + input: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + scores: + compliance: + "$serde_json::private::Number": "3" + customerSatisfaction: + "$serde_json::private::Number": "4" + delivery: + "$serde_json::private::Number": "4" + inventory: + "$serde_json::private::Number": "4" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + name: aggregate_scores + order: + "$serde_json::private::Number": "5" + output: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + scores: + averageScore: + "$serde_json::private::Number": "3.75" + compliance: + "$serde_json::private::Number": "3" + customerSatisfaction: + "$serde_json::private::Number": "4" + delivery: + "$serde_json::private::Number": "4" + improvements: [] + inventory: + "$serde_json::private::Number": "4" + strengths: + - customerSatisfaction + - inventory + - delivery + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + performance: "[perf]" + traceData: + averageScore: + result: "3.75" + improvements: + result: "[]" + strengths: + result: "[\"customerSatisfaction\",\"inventory\",\"delivery\"]" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + metrics: + customerSatisfaction: + "$serde_json::private::Number": "4.7" + inventoryAccuracy: + "$serde_json::private::Number": "97.2" + onTimeDeliveryRate: + "$serde_json::private::Number": "96.5" + policyCompliance: + "$serde_json::private::Number": "94.8" + sellerInfo: + id: S12345 + monthsActive: + "$serde_json::private::Number": "18" + name: Global Gadgets Store + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__medical-appointment-priority-system_0.snap b/core/engine/tests/snapshots/engine__medical-appointment-priority-system_0.snap new file mode 100644 index 00000000..14a2d0d5 --- /dev/null +++ b/core/engine/tests/snapshots/engine__medical-appointment-priority-system_0.snap @@ -0,0 +1,391 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + priorityFactors: + - Moderate condition with follow-up + - Moderate wait time (8-14 days) + - Age over 65 + - Chronic condition + - Recent hospitalization + result: + priority: HIGH + recommendation: Schedule within 24-48 hours + scores: + conditionSeverity: + "$serde_json::private::Number": "20" + riskFactors: + "$serde_json::private::Number": "40" + waitTime: + "$serde_json::private::Number": "10" + totalScore: + "$serde_json::private::Number": "70" +trace: + 02b0be40-dfe0-4a11-a9a4-17f66823f0c2: + id: 02b0be40-dfe0-4a11-a9a4-17f66823f0c2 + input: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + riskFactors: + - message: Age over 65 + score: + "$serde_json::private::Number": "10" + - message: Chronic condition + score: + "$serde_json::private::Number": "15" + - message: Recent hospitalization + score: + "$serde_json::private::Number": "15" + name: riskFactorSummary + order: + "$serde_json::private::Number": "2" + output: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + reasons: + riskFactors: + - Age over 65 + - Chronic condition + - Recent hospitalization + scores: + riskFactors: + "$serde_json::private::Number": "40" + performance: "[perf]" + traceData: + reasons.riskFactors: + result: "[\"Age over 65\",\"Chronic condition\",\"Recent hospitalization\"]" + riskFactors: + result: "null" + scores.riskFactors: + result: "40" + conditionSeverityNode: + id: conditionSeverityNode + input: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + reasons: + riskFactors: + - Age over 65 + - Chronic condition + - Recent hospitalization + scores: + riskFactors: + "$serde_json::private::Number": "40" + name: evaluateConditionSeverity + order: + "$serde_json::private::Number": "3" + output: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + reasons: + conditionSeverity: Moderate condition with follow-up + riskFactors: + - Age over 65 + - Chronic condition + - Recent hospitalization + scores: + conditionSeverity: + "$serde_json::private::Number": "20" + riskFactors: + "$serde_json::private::Number": "40" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + appointment.conditionSeverity: moderate + appointment.isFollowUp: true + rule: + _id: severity3 + "appointment.conditionSeverity[i2-1]": "'moderate'" + "appointment.isFollowUp[i2-2]": "true" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + performance: "[perf]" + traceData: ~ + priorityAssignmentNode: + id: priorityAssignmentNode + input: + priorityFactors: + - Moderate condition with follow-up + - Moderate wait time (8-14 days) + - Age over 65 + - Chronic condition + - Recent hospitalization + scores: + conditionSeverity: + "$serde_json::private::Number": "20" + riskFactors: + "$serde_json::private::Number": "40" + waitTime: + "$serde_json::private::Number": "10" + totalScore: + "$serde_json::private::Number": "70" + name: assignPriorityLevel + order: + "$serde_json::private::Number": "6" + output: + priorityFactors: + - Moderate condition with follow-up + - Moderate wait time (8-14 days) + - Age over 65 + - Chronic condition + - Recent hospitalization + result: + priority: HIGH + recommendation: Schedule within 24-48 hours + scores: + conditionSeverity: + "$serde_json::private::Number": "20" + riskFactors: + "$serde_json::private::Number": "40" + waitTime: + "$serde_json::private::Number": "10" + totalScore: + "$serde_json::private::Number": "70" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + totalScore: + "$serde_json::private::Number": "70" + rule: + _id: priority2 + "totalScore[i4-1]": ">= 60" + riskFactorScoreNode: + id: riskFactorScoreNode + input: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + name: calculateRiskFactorScore + order: + "$serde_json::private::Number": "1" + output: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + riskFactors: + - message: Age over 65 + score: + "$serde_json::private::Number": "10" + - message: Chronic condition + score: + "$serde_json::private::Number": "15" + - message: Recent hospitalization + score: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _description: "" + _id: risk1 + - index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _description: "" + _id: risk2 + - index: + "$serde_json::private::Number": "3" + reference_map: {} + rule: + _description: "" + _id: risk4 + totalPriorityScoreNode: + id: totalPriorityScoreNode + input: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + reasons: + conditionSeverity: Moderate condition with follow-up + riskFactors: + - Age over 65 + - Chronic condition + - Recent hospitalization + waitTime: Moderate wait time (8-14 days) + scores: + conditionSeverity: + "$serde_json::private::Number": "20" + riskFactors: + "$serde_json::private::Number": "40" + waitTime: + "$serde_json::private::Number": "10" + name: calculateTotalPriorityScore + order: + "$serde_json::private::Number": "5" + output: + priorityFactors: + - Moderate condition with follow-up + - Moderate wait time (8-14 days) + - Age over 65 + - Chronic condition + - Recent hospitalization + scores: + conditionSeverity: + "$serde_json::private::Number": "20" + riskFactors: + "$serde_json::private::Number": "40" + waitTime: + "$serde_json::private::Number": "10" + totalScore: + "$serde_json::private::Number": "70" + performance: "[perf]" + traceData: + appointment: + result: "null" + patient: + result: "null" + priorityFactors: + result: "[\"Moderate condition with follow-up\",\"Moderate wait time (8-14 days)\",\"Age over 65\",\"Chronic condition\",\"Recent hospitalization\"]" + reasons: + result: "null" + totalScore: + result: "70" + waitTimeScoreNode: + id: waitTimeScoreNode + input: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + reasons: + conditionSeverity: Moderate condition with follow-up + riskFactors: + - Age over 65 + - Chronic condition + - Recent hospitalization + scores: + conditionSeverity: + "$serde_json::private::Number": "20" + riskFactors: + "$serde_json::private::Number": "40" + name: calculateWaitTimeScore + order: + "$serde_json::private::Number": "4" + output: + appointment: + conditionSeverity: moderate + daysWaiting: + "$serde_json::private::Number": "12" + isFollowUp: true + patient: + age: + "$serde_json::private::Number": "72" + hasChronicCondition: true + immunocompromised: false + recentHospitalization: true + reasons: + conditionSeverity: Moderate condition with follow-up + riskFactors: + - Age over 65 + - Chronic condition + - Recent hospitalization + waitTime: Moderate wait time (8-14 days) + scores: + conditionSeverity: + "$serde_json::private::Number": "20" + riskFactors: + "$serde_json::private::Number": "40" + waitTime: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + appointment.daysWaiting: + "$serde_json::private::Number": "12" + rule: + _id: wait3 + "appointment.daysWaiting[i3-1]": "> 7" diff --git a/core/engine/tests/snapshots/engine__medication-dosage-calculator_0.snap b/core/engine/tests/snapshots/engine__medication-dosage-calculator_0.snap new file mode 100644 index 00000000..60486f12 --- /dev/null +++ b/core/engine/tests/snapshots/engine__medication-dosage-calculator_0.snap @@ -0,0 +1,163 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + calculatedDose: + adjustmentReason: adjusted for renal function + amount: + "$serde_json::private::Number": "731.25" + frequencyHours: "12" + route: intravenous + unit: mg +trace: + dt1: + id: dt1 + input: + ageYears: + "$serde_json::private::Number": "72" + allergies: + - penicillin + - sulfa + currentMedications: + - metformin + - lisinopril + gfrValue: + "$serde_json::private::Number": "45" + hasLiverImpairment: false + hasRenalImpairment: true + isChild: false + isElderly: true + liverAdjustmentFactor: + "$serde_json::private::Number": "1" + liverFunction: normal + medication: vancomycin + patientId: P12345 + renalAdjustmentFactor: + "$serde_json::private::Number": "0.75" + weightFactorAdult: + "$serde_json::private::Number": "0.9285714285714285714285714286" + weightFactorChild: + "$serde_json::private::Number": "2.1666666666666666666666666667" + weightKg: + "$serde_json::private::Number": "65" + name: calculateDosage + order: + "$serde_json::private::Number": "2" + output: + calculatedDose: + adjustmentReason: adjusted for renal function + amount: + "$serde_json::private::Number": "731.25" + frequencyHours: "12" + route: intravenous + unit: mg + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "5" + reference_map: + hasLiverImpairment: false + hasRenalImpairment: true + isChild: false + isElderly: true + medication: vancomycin + rule: + _id: r1-6 + "hasLiverImpairment[i1-5]": "" + "hasRenalImpairment[i1-4]": "true" + "isChild[i1-2]": "" + "isElderly[i1-3]": "" + "medication[i1-1]": "'vancomycin'" + ex1: + id: ex1 + input: + ageYears: + "$serde_json::private::Number": "72" + allergies: + - penicillin + - sulfa + currentMedications: + - metformin + - lisinopril + gfrValue: + "$serde_json::private::Number": "45" + liverFunction: normal + medication: vancomycin + patientId: P12345 + weightKg: + "$serde_json::private::Number": "65" + name: calculateParameters + order: + "$serde_json::private::Number": "1" + output: + ageYears: + "$serde_json::private::Number": "72" + allergies: + - penicillin + - sulfa + currentMedications: + - metformin + - lisinopril + gfrValue: + "$serde_json::private::Number": "45" + hasLiverImpairment: false + hasRenalImpairment: true + isChild: false + isElderly: true + liverAdjustmentFactor: + "$serde_json::private::Number": "1" + liverFunction: normal + medication: vancomycin + patientId: P12345 + renalAdjustmentFactor: + "$serde_json::private::Number": "0.75" + weightFactorAdult: + "$serde_json::private::Number": "0.9285714285714285714285714286" + weightFactorChild: + "$serde_json::private::Number": "2.1666666666666666666666666667" + weightKg: + "$serde_json::private::Number": "65" + performance: "[perf]" + traceData: + hasLiverImpairment: + result: "false" + hasRenalImpairment: + result: "true" + isChild: + result: "false" + isElderly: + result: "true" + liverAdjustmentFactor: + result: "1" + renalAdjustmentFactor: + result: "0.75" + weightFactorAdult: + result: "0.9285714285714285714285714286" + weightFactorChild: + result: "2.1666666666666666666666666667" + ip1: + id: ip1 + input: ~ + name: patientData + order: + "$serde_json::private::Number": "0" + output: + ageYears: + "$serde_json::private::Number": "72" + allergies: + - penicillin + - sulfa + currentMedications: + - metformin + - lisinopril + gfrValue: + "$serde_json::private::Number": "45" + liverFunction: normal + medication: vancomycin + patientId: P12345 + weightKg: + "$serde_json::private::Number": "65" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__merch-bags_0.snap b/core/engine/tests/snapshots/engine__merch-bags_0.snap new file mode 100644 index 00000000..5d304ff9 --- /dev/null +++ b/core/engine/tests/snapshots/engine__merch-bags_0.snap @@ -0,0 +1,58 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + code: BAG10 + price: + "$serde_json::private::Number": "12" +trace: + 36aa02a4-df14-4c54-a852-175e749d5860: + id: 36aa02a4-df14-4c54-a852-175e749d5860 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + class: economy + origin: JFK + performance: "[perf]" + traceData: ~ + 5d03a351-786f-4f7d-9b2b-709dc0d81460: + id: 5d03a351-786f-4f7d-9b2b-709dc0d81460 + input: + class: economy + origin: JFK + name: Bags + order: + "$serde_json::private::Number": "1" + output: + code: BAG10 + price: + "$serde_json::private::Number": "12" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + class: economy + destination: ~ + origin: JFK + rule: + _id: a6083cab-8dfe-46ae-acf3-823e02ca3f3b + "class[b2e2476f-5340-4d66-aec0-9a282be0e716]": "\"economy\"" + "destination[UmZtXogtD7]": "" + "origin[a9711b12-1d29-40a3-a48f-2c03df5c8aff]": "\"JFK\"" + f42391bc-6183-4b12-8eaa-6b56510c17ef: + id: f42391bc-6183-4b12-8eaa-6b56510c17ef + input: + code: BAG10 + price: + "$serde_json::private::Number": "12" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__merch-bags_1.snap b/core/engine/tests/snapshots/engine__merch-bags_1.snap new file mode 100644 index 00000000..4f2d31b1 --- /dev/null +++ b/core/engine/tests/snapshots/engine__merch-bags_1.snap @@ -0,0 +1,60 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + code: BAG10 + price: + "$serde_json::private::Number": "10" +trace: + 36aa02a4-df14-4c54-a852-175e749d5860: + id: 36aa02a4-df14-4c54-a852-175e749d5860 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + class: economy + destination: LAX + origin: JFK + performance: "[perf]" + traceData: ~ + 5d03a351-786f-4f7d-9b2b-709dc0d81460: + id: 5d03a351-786f-4f7d-9b2b-709dc0d81460 + input: + class: economy + destination: LAX + origin: JFK + name: Bags + order: + "$serde_json::private::Number": "1" + output: + code: BAG10 + price: + "$serde_json::private::Number": "10" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + class: economy + destination: LAX + origin: JFK + rule: + _id: a882b24f-b796-435e-a116-d7e6e5214ff6 + "class[b2e2476f-5340-4d66-aec0-9a282be0e716]": "\"economy\"" + "destination[UmZtXogtD7]": "\"LAX\"" + "origin[a9711b12-1d29-40a3-a48f-2c03df5c8aff]": "\"JFK\"" + f42391bc-6183-4b12-8eaa-6b56510c17ef: + id: f42391bc-6183-4b12-8eaa-6b56510c17ef + input: + code: BAG10 + price: + "$serde_json::private::Number": "10" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__merch-bags_2.snap b/core/engine/tests/snapshots/engine__merch-bags_2.snap new file mode 100644 index 00000000..3591c350 --- /dev/null +++ b/core/engine/tests/snapshots/engine__merch-bags_2.snap @@ -0,0 +1,63 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + code: BAG23 + included: true + price: + "$serde_json::private::Number": "0" +trace: + 36aa02a4-df14-4c54-a852-175e749d5860: + id: 36aa02a4-df14-4c54-a852-175e749d5860 + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + class: business + destination: LAX + origin: JFK + performance: "[perf]" + traceData: ~ + 5d03a351-786f-4f7d-9b2b-709dc0d81460: + id: 5d03a351-786f-4f7d-9b2b-709dc0d81460 + input: + class: business + destination: LAX + origin: JFK + name: Bags + order: + "$serde_json::private::Number": "1" + output: + code: BAG23 + included: true + price: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + class: business + destination: LAX + origin: JFK + rule: + _id: 731388b9-9e94-499a-b201-3f107e7e8a54 + "class[b2e2476f-5340-4d66-aec0-9a282be0e716]": "\"business\", \"first\"" + "destination[UmZtXogtD7]": "" + "origin[a9711b12-1d29-40a3-a48f-2c03df5c8aff]": "" + f42391bc-6183-4b12-8eaa-6b56510c17ef: + id: f42391bc-6183-4b12-8eaa-6b56510c17ef + input: + code: BAG23 + included: true + price: + "$serde_json::private::Number": "0" + name: Response + order: + "$serde_json::private::Number": "2" + output: ~ + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__multi-switch_0.snap b/core/engine/tests/snapshots/engine__multi-switch_0.snap new file mode 100644 index 00000000..981314ac --- /dev/null +++ b/core/engine/tests/snapshots/engine__multi-switch_0.snap @@ -0,0 +1,81 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + flag: + turnover: red +trace: + 2ee16c8c-fb12-4f20-9813-67bad6f4eb14: + id: 2ee16c8c-fb12-4f20-9813-67bad6f4eb14 + input: + company: + type: LLC + name: Model Turnover LLC + order: + "$serde_json::private::Number": "3" + output: + flag: + turnover: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + company.turnover: ~ + rule: + _id: 952300fd-e4d9-4301-8a5a-4eda1d01d8ee + "company.turnover[fa0fd31a-8865-43fb-8a60-b729c640140a]": "" + 84b0e11b-8c9d-46f3-ac34-f674f3b98068: + id: 84b0e11b-8c9d-46f3-ac34-f674f3b98068 + input: + flag: + turnover: red + name: Response + order: + "$serde_json::private::Number": "4" + output: ~ + performance: "[perf]" + traceData: ~ + dc7b8739-e234-4363-afe9-df156f082f6f: + id: dc7b8739-e234-4363-afe9-df156f082f6f + input: + company: + type: LLC + name: switchNode 1 + order: + "$serde_json::private::Number": "2" + output: + company: + type: LLC + performance: "[perf]" + traceData: + statements: + - id: 931eda5b-a780-428b-9a0a-e3eb6283bab4 + de6cc00d-ef1b-46f5-9beb-9285d468c39d: + id: de6cc00d-ef1b-46f5-9beb-9285d468c39d + input: + company: + type: LLC + name: switchNode 1 + order: + "$serde_json::private::Number": "1" + output: + company: + type: LLC + performance: "[perf]" + traceData: + statements: + - id: 6499e0bb-2cda-4a5f-9246-d48e7d2177fb + fecde070-38cf-4656-81d7-3a2cb6e38f8f: + id: fecde070-38cf-4656-81d7-3a2cb6e38f8f + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + company: + type: LLC + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__multi-switch_1.snap b/core/engine/tests/snapshots/engine__multi-switch_1.snap new file mode 100644 index 00000000..3e4755fe --- /dev/null +++ b/core/engine/tests/snapshots/engine__multi-switch_1.snap @@ -0,0 +1,126 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + flag: + secretaries: amber + turnover: red +trace: + 2ee16c8c-fb12-4f20-9813-67bad6f4eb14: + id: 2ee16c8c-fb12-4f20-9813-67bad6f4eb14 + input: + company: + secretaries: + - first + - second + type: LLC + name: Model Turnover LLC + order: + "$serde_json::private::Number": "4" + output: + flag: + turnover: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + company.turnover: ~ + rule: + _id: 952300fd-e4d9-4301-8a5a-4eda1d01d8ee + "company.turnover[fa0fd31a-8865-43fb-8a60-b729c640140a]": "" + 49f76396-88ae-4808-a6db-65091d5be0c7: + id: 49f76396-88ae-4808-a6db-65091d5be0c7 + input: + company: + secretaries: + - first + - second + type: LLC + name: Model 1a + order: + "$serde_json::private::Number": "3" + output: + flag: + secretaries: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + len(company.secretaries): + "$serde_json::private::Number": "2" + rule: + _id: c6cc83a2-3b57-4c21-b2e9-a5753c1714cc + "len(company.secretaries)[d34e312e-3c73-4e7f-a384-8c7b63d226cc]": "> 1" + 84b0e11b-8c9d-46f3-ac34-f674f3b98068: + id: 84b0e11b-8c9d-46f3-ac34-f674f3b98068 + input: + flag: + secretaries: amber + turnover: red + name: Response + order: + "$serde_json::private::Number": "5" + output: ~ + performance: "[perf]" + traceData: ~ + dc7b8739-e234-4363-afe9-df156f082f6f: + id: dc7b8739-e234-4363-afe9-df156f082f6f + input: + company: + secretaries: + - first + - second + type: LLC + name: switchNode 1 + order: + "$serde_json::private::Number": "2" + output: + company: + secretaries: + - first + - second + type: LLC + performance: "[perf]" + traceData: + statements: + - id: e672a228-ff6b-4859-a017-ab5e5c125b60 + - id: 931eda5b-a780-428b-9a0a-e3eb6283bab4 + de6cc00d-ef1b-46f5-9beb-9285d468c39d: + id: de6cc00d-ef1b-46f5-9beb-9285d468c39d + input: + company: + secretaries: + - first + - second + type: LLC + name: switchNode 1 + order: + "$serde_json::private::Number": "1" + output: + company: + secretaries: + - first + - second + type: LLC + performance: "[perf]" + traceData: + statements: + - id: 6499e0bb-2cda-4a5f-9246-d48e7d2177fb + fecde070-38cf-4656-81d7-3a2cb6e38f8f: + id: fecde070-38cf-4656-81d7-3a2cb6e38f8f + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + company: + secretaries: + - first + - second + type: LLC + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__multi-switch_2.snap b/core/engine/tests/snapshots/engine__multi-switch_2.snap new file mode 100644 index 00000000..34fb3de0 --- /dev/null +++ b/core/engine/tests/snapshots/engine__multi-switch_2.snap @@ -0,0 +1,177 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + flag: + directors: red + secretaries: amber + turnover: red +trace: + 2ee16c8c-fb12-4f20-9813-67bad6f4eb14: + id: 2ee16c8c-fb12-4f20-9813-67bad6f4eb14 + input: + company: + directors: + - first + - second + secretaries: + - first + - second + type: LLC + name: Model Turnover LLC + order: + "$serde_json::private::Number": "5" + output: + flag: + turnover: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + company.turnover: ~ + rule: + _id: 952300fd-e4d9-4301-8a5a-4eda1d01d8ee + "company.turnover[fa0fd31a-8865-43fb-8a60-b729c640140a]": "" + 49f76396-88ae-4808-a6db-65091d5be0c7: + id: 49f76396-88ae-4808-a6db-65091d5be0c7 + input: + company: + directors: + - first + - second + secretaries: + - first + - second + type: LLC + name: Model 1a + order: + "$serde_json::private::Number": "4" + output: + flag: + secretaries: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + len(company.secretaries): + "$serde_json::private::Number": "2" + rule: + _id: c6cc83a2-3b57-4c21-b2e9-a5753c1714cc + "len(company.secretaries)[d34e312e-3c73-4e7f-a384-8c7b63d226cc]": "> 1" + 84b0e11b-8c9d-46f3-ac34-f674f3b98068: + id: 84b0e11b-8c9d-46f3-ac34-f674f3b98068 + input: + flag: + directors: red + secretaries: amber + turnover: red + name: Response + order: + "$serde_json::private::Number": "6" + output: ~ + performance: "[perf]" + traceData: ~ + ab1b450a-ce21-4d99-8de6-4e4deeb37d75: + id: ab1b450a-ce21-4d99-8de6-4e4deeb37d75 + input: + company: + directors: + - first + - second + secretaries: + - first + - second + type: LLC + name: Model 1b + order: + "$serde_json::private::Number": "3" + output: + flag: + directors: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + len(company.directors): + "$serde_json::private::Number": "2" + rule: + _id: 171ec41f-ac79-4926-a24f-c8d227879989 + "len(company.directors)[014f4025-ddb0-48c3-9e79-aa60368b485b]": "" + dc7b8739-e234-4363-afe9-df156f082f6f: + id: dc7b8739-e234-4363-afe9-df156f082f6f + input: + company: + directors: + - first + - second + secretaries: + - first + - second + type: LLC + name: switchNode 1 + order: + "$serde_json::private::Number": "2" + output: + company: + directors: + - first + - second + secretaries: + - first + - second + type: LLC + performance: "[perf]" + traceData: + statements: + - id: e672a228-ff6b-4859-a017-ab5e5c125b60 + - id: 5ba3e324-a4fa-4e5f-8523-db21b47b32b6 + - id: 931eda5b-a780-428b-9a0a-e3eb6283bab4 + de6cc00d-ef1b-46f5-9beb-9285d468c39d: + id: de6cc00d-ef1b-46f5-9beb-9285d468c39d + input: + company: + directors: + - first + - second + secretaries: + - first + - second + type: LLC + name: switchNode 1 + order: + "$serde_json::private::Number": "1" + output: + company: + directors: + - first + - second + secretaries: + - first + - second + type: LLC + performance: "[perf]" + traceData: + statements: + - id: 6499e0bb-2cda-4a5f-9246-d48e7d2177fb + fecde070-38cf-4656-81d7-3a2cb6e38f8f: + id: fecde070-38cf-4656-81d7-3a2cb6e38f8f + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + company: + directors: + - first + - second + secretaries: + - first + - second + type: LLC + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__multi-switch_3.snap b/core/engine/tests/snapshots/engine__multi-switch_3.snap new file mode 100644 index 00000000..cb7bef9f --- /dev/null +++ b/core/engine/tests/snapshots/engine__multi-switch_3.snap @@ -0,0 +1,162 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + flag: + secretaries: red + turnover: amber +trace: + 2b06eb6e-f3ed-4a9e-9f36-a0de372d97fe: + id: 2b06eb6e-f3ed-4a9e-9f36-a0de372d97fe + input: + company: + directors: + - first + - second + secretaries: + - first + - second + turnover: + "$serde_json::private::Number": "10000000" + type: Corporation + name: switchNode 1 + order: + "$serde_json::private::Number": "2" + output: + company: + directors: + - first + - second + secretaries: + - first + - second + turnover: + "$serde_json::private::Number": "10000000" + type: Corporation + performance: "[perf]" + traceData: + statements: + - id: 2ce01e42-e125-4184-9a8d-2a7ccf8daf14 + - id: 3fba0ac2-8498-4421-bb1d-c0c8cabd9c39 + 71100c8d-ae90-4529-904e-b3741298b739: + id: 71100c8d-ae90-4529-904e-b3741298b739 + input: + company: + directors: + - first + - second + secretaries: + - first + - second + turnover: + "$serde_json::private::Number": "10000000" + type: Corporation + name: Model 2b + order: + "$serde_json::private::Number": "3" + output: + flag: + secretaries: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + len(company.secretaries): + "$serde_json::private::Number": "2" + rule: + _id: 3877b676-e4ff-4479-910d-8fa9d32809d6 + "len(company.secretaries)[9705e5a5-a590-40da-b1a0-43e6af121e1b]": "" + d29b5884-76fc-4c55-8646-3d3417e5b366: + id: d29b5884-76fc-4c55-8646-3d3417e5b366 + input: + flag: + secretaries: red + turnover: amber + name: Response + order: + "$serde_json::private::Number": "5" + output: ~ + performance: "[perf]" + traceData: ~ + de6cc00d-ef1b-46f5-9beb-9285d468c39d: + id: de6cc00d-ef1b-46f5-9beb-9285d468c39d + input: + company: + directors: + - first + - second + secretaries: + - first + - second + turnover: + "$serde_json::private::Number": "10000000" + type: Corporation + name: switchNode 1 + order: + "$serde_json::private::Number": "1" + output: + company: + directors: + - first + - second + secretaries: + - first + - second + turnover: + "$serde_json::private::Number": "10000000" + type: Corporation + performance: "[perf]" + traceData: + statements: + - id: 597a39af-4be4-4626-8de9-c110527a49bb + fecde070-38cf-4656-81d7-3a2cb6e38f8f: + id: fecde070-38cf-4656-81d7-3a2cb6e38f8f + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + company: + directors: + - first + - second + secretaries: + - first + - second + turnover: + "$serde_json::private::Number": "10000000" + type: Corporation + performance: "[perf]" + traceData: ~ + ff35357b-2a9f-4eb0-aaee-edb56e3a0ca2: + id: ff35357b-2a9f-4eb0-aaee-edb56e3a0ca2 + input: + company: + directors: + - first + - second + secretaries: + - first + - second + turnover: + "$serde_json::private::Number": "10000000" + type: Corporation + name: Model Turnover Corp + order: + "$serde_json::private::Number": "4" + output: + flag: + turnover: amber + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + company.turnover: + "$serde_json::private::Number": "10000000" + rule: + _id: 6a967f72-ee4d-407d-ad16-d0695170222e + "company.turnover[fa0fd31a-8865-43fb-8a60-b729c640140a]": "[1000000..10000000]" diff --git a/core/engine/tests/snapshots/engine__multi-switch_4.snap b/core/engine/tests/snapshots/engine__multi-switch_4.snap new file mode 100644 index 00000000..1f83a868 --- /dev/null +++ b/core/engine/tests/snapshots/engine__multi-switch_4.snap @@ -0,0 +1,147 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + flag: + secretaries: red + turnover: red +trace: + 2b06eb6e-f3ed-4a9e-9f36-a0de372d97fe: + id: 2b06eb6e-f3ed-4a9e-9f36-a0de372d97fe + input: + company: + directors: + - first + - second + secretaries: + - first + - second + type: Corporation + name: switchNode 1 + order: + "$serde_json::private::Number": "2" + output: + company: + directors: + - first + - second + secretaries: + - first + - second + type: Corporation + performance: "[perf]" + traceData: + statements: + - id: 2ce01e42-e125-4184-9a8d-2a7ccf8daf14 + - id: 3fba0ac2-8498-4421-bb1d-c0c8cabd9c39 + 71100c8d-ae90-4529-904e-b3741298b739: + id: 71100c8d-ae90-4529-904e-b3741298b739 + input: + company: + directors: + - first + - second + secretaries: + - first + - second + type: Corporation + name: Model 2b + order: + "$serde_json::private::Number": "3" + output: + flag: + secretaries: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + len(company.secretaries): + "$serde_json::private::Number": "2" + rule: + _id: 3877b676-e4ff-4479-910d-8fa9d32809d6 + "len(company.secretaries)[9705e5a5-a590-40da-b1a0-43e6af121e1b]": "" + d29b5884-76fc-4c55-8646-3d3417e5b366: + id: d29b5884-76fc-4c55-8646-3d3417e5b366 + input: + flag: + secretaries: red + turnover: red + name: Response + order: + "$serde_json::private::Number": "5" + output: ~ + performance: "[perf]" + traceData: ~ + de6cc00d-ef1b-46f5-9beb-9285d468c39d: + id: de6cc00d-ef1b-46f5-9beb-9285d468c39d + input: + company: + directors: + - first + - second + secretaries: + - first + - second + type: Corporation + name: switchNode 1 + order: + "$serde_json::private::Number": "1" + output: + company: + directors: + - first + - second + secretaries: + - first + - second + type: Corporation + performance: "[perf]" + traceData: + statements: + - id: 597a39af-4be4-4626-8de9-c110527a49bb + fecde070-38cf-4656-81d7-3a2cb6e38f8f: + id: fecde070-38cf-4656-81d7-3a2cb6e38f8f + input: ~ + name: Request + order: + "$serde_json::private::Number": "0" + output: + company: + directors: + - first + - second + secretaries: + - first + - second + type: Corporation + performance: "[perf]" + traceData: ~ + ff35357b-2a9f-4eb0-aaee-edb56e3a0ca2: + id: ff35357b-2a9f-4eb0-aaee-edb56e3a0ca2 + input: + company: + directors: + - first + - second + secretaries: + - first + - second + type: Corporation + name: Model Turnover Corp + order: + "$serde_json::private::Number": "4" + output: + flag: + turnover: red + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + company.turnover: ~ + rule: + _id: 4b7953b5-a8dc-4a1e-9412-32a038eab1bf + "company.turnover[fa0fd31a-8865-43fb-8a60-b729c640140a]": "" diff --git a/core/engine/tests/snapshots/engine__municipal-permit-evaluation-system_0.snap b/core/engine/tests/snapshots/engine__municipal-permit-evaluation-system_0.snap new file mode 100644 index 00000000..9b91b508 --- /dev/null +++ b/core/engine/tests/snapshots/engine__municipal-permit-evaluation-system_0.snap @@ -0,0 +1,269 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + applicantInfo: + contactEmail: john.smith@example.com + name: John Smith + phoneNumber: 555-123-4567 + applicationType: building + approvalReason: Application approved - Minimal environmental impact + approvalStatus: Approved + buildingHeight: + "$serde_json::private::Number": "28" + environmentalImpact: minimal + initialApprovalStatus: Approved + isCommercialZone: false + isIndoorEvent: false + isIndustrialZone: false + isOutdoorEvent: false + isResidentialZone: true + nextSteps: standard + projectDescription: Single-family home construction with attached garage + propertyAddress: + city: Anytown + state: CA + street: 123 Main Street + zipCode: "90210" + safetyScore: + "$serde_json::private::Number": "85" + squareFootage: + "$serde_json::private::Number": "3200" + statusReason: Residential building meets height and safety requirements + zoneType: residential +trace: + dt1: + id: dt1 + input: + applicantInfo: + contactEmail: john.smith@example.com + name: John Smith + phoneNumber: 555-123-4567 + applicationType: building + buildingHeight: + "$serde_json::private::Number": "28" + environmentalImpact: minimal + isCommercialZone: false + isIndoorEvent: false + isIndustrialZone: false + isOutdoorEvent: false + isResidentialZone: true + projectDescription: Single-family home construction with attached garage + propertyAddress: + city: Anytown + state: CA + street: 123 Main Street + zipCode: "90210" + safetyScore: + "$serde_json::private::Number": "85" + squareFootage: + "$serde_json::private::Number": "3200" + zoneType: residential + name: initialApprovalCheck + order: + "$serde_json::private::Number": "2" + output: + applicantInfo: + contactEmail: john.smith@example.com + name: John Smith + phoneNumber: 555-123-4567 + applicationType: building + buildingHeight: + "$serde_json::private::Number": "28" + environmentalImpact: minimal + initialApprovalStatus: Approved + isCommercialZone: false + isIndoorEvent: false + isIndustrialZone: false + isOutdoorEvent: false + isResidentialZone: true + projectDescription: Single-family home construction with attached garage + propertyAddress: + city: Anytown + state: CA + street: 123 Main Street + zipCode: "90210" + safetyScore: + "$serde_json::private::Number": "85" + squareFootage: + "$serde_json::private::Number": "3200" + statusReason: Residential building meets height and safety requirements + zoneType: residential + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + safetyScore: + "$serde_json::private::Number": "85" + squareFootage: + "$serde_json::private::Number": "3200" + rule: + _id: r1-1 + "safetyScore[i1-3]": ">= 80" + "squareFootage[i1-2]": "< 5000" + dt2: + id: dt2 + input: + applicantInfo: + contactEmail: john.smith@example.com + name: John Smith + phoneNumber: 555-123-4567 + applicationType: building + buildingHeight: + "$serde_json::private::Number": "28" + environmentalImpact: minimal + initialApprovalStatus: Approved + isCommercialZone: false + isIndoorEvent: false + isIndustrialZone: false + isOutdoorEvent: false + isResidentialZone: true + projectDescription: Single-family home construction with attached garage + propertyAddress: + city: Anytown + state: CA + street: 123 Main Street + zipCode: "90210" + safetyScore: + "$serde_json::private::Number": "85" + squareFootage: + "$serde_json::private::Number": "3200" + statusReason: Residential building meets height and safety requirements + zoneType: residential + name: environmentalCheck + order: + "$serde_json::private::Number": "3" + output: + applicantInfo: + contactEmail: john.smith@example.com + name: John Smith + phoneNumber: 555-123-4567 + applicationType: building + approvalReason: Application approved - Minimal environmental impact + approvalStatus: Approved + buildingHeight: + "$serde_json::private::Number": "28" + environmentalImpact: minimal + initialApprovalStatus: Approved + isCommercialZone: false + isIndoorEvent: false + isIndustrialZone: false + isOutdoorEvent: false + isResidentialZone: true + nextSteps: standard + projectDescription: Single-family home construction with attached garage + propertyAddress: + city: Anytown + state: CA + street: 123 Main Street + zipCode: "90210" + safetyScore: + "$serde_json::private::Number": "85" + squareFootage: + "$serde_json::private::Number": "3200" + statusReason: Residential building meets height and safety requirements + zoneType: residential + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + environmentalImpact: minimal + initialApprovalStatus: Approved + rule: + _id: r2-1 + "environmentalImpact[i2-2]": "'minimal'" + "initialApprovalStatus[i2-1]": "'Approved'" + ex1: + id: ex1 + input: + applicantInfo: + contactEmail: john.smith@example.com + name: John Smith + phoneNumber: 555-123-4567 + applicationType: building + buildingHeight: + "$serde_json::private::Number": "28" + environmentalImpact: minimal + projectDescription: Single-family home construction with attached garage + propertyAddress: + city: Anytown + state: CA + street: 123 Main Street + zipCode: "90210" + safetyScore: + "$serde_json::private::Number": "85" + squareFootage: + "$serde_json::private::Number": "3200" + zoneType: residential + name: applicationClassification + order: + "$serde_json::private::Number": "1" + output: + applicantInfo: + contactEmail: john.smith@example.com + name: John Smith + phoneNumber: 555-123-4567 + applicationType: building + buildingHeight: + "$serde_json::private::Number": "28" + environmentalImpact: minimal + isCommercialZone: false + isIndoorEvent: false + isIndustrialZone: false + isOutdoorEvent: false + isResidentialZone: true + projectDescription: Single-family home construction with attached garage + propertyAddress: + city: Anytown + state: CA + street: 123 Main Street + zipCode: "90210" + safetyScore: + "$serde_json::private::Number": "85" + squareFootage: + "$serde_json::private::Number": "3200" + zoneType: residential + performance: "[perf]" + traceData: + isCommercialZone: + result: "false" + isIndoorEvent: + result: "false" + isIndustrialZone: + result: "false" + isOutdoorEvent: + result: "false" + isResidentialZone: + result: "true" + ip1: + id: ip1 + input: ~ + name: permitRequest + order: + "$serde_json::private::Number": "0" + output: + applicantInfo: + contactEmail: john.smith@example.com + name: John Smith + phoneNumber: 555-123-4567 + applicationType: building + buildingHeight: + "$serde_json::private::Number": "28" + environmentalImpact: minimal + projectDescription: Single-family home construction with attached garage + propertyAddress: + city: Anytown + state: CA + street: 123 Main Street + zipCode: "90210" + safetyScore: + "$serde_json::private::Number": "85" + squareFootage: + "$serde_json::private::Number": "3200" + zoneType: residential + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__mvno-partner-enablement_0.snap b/core/engine/tests/snapshots/engine__mvno-partner-enablement_0.snap new file mode 100644 index 00000000..8d6ad24f --- /dev/null +++ b/core/engine/tests/snapshots/engine__mvno-partner-enablement_0.snap @@ -0,0 +1,177 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + pricing: + dataRatePerMB: + "$serde_json::private::Number": "0.004" + revenueShareFactor: + "$serde_json::private::Number": "0.85" + tier: tier1 + voiceRatePerMinute: + "$serde_json::private::Number": "0.002" +trace: + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + partner: + ageInMonths: + "$serde_json::private::Number": "36" + businessModel: business-focused + id: mvno-123 + name: TechMobile + region: Northeast + subscriberCount: + "$serde_json::private::Number": "120000" + type: premium + performance: "[perf]" + traceData: ~ + partnerConfig: + id: partnerConfig + input: + partner: + ageInMonths: + "$serde_json::private::Number": "36" + businessModel: business-focused + id: mvno-123 + name: TechMobile + region: Northeast + subscriberCount: + "$serde_json::private::Number": "120000" + type: premium + name: partnerServiceAccess + order: + "$serde_json::private::Number": "1" + output: + config: + bandwidthPriority: high + serviceAccessLevel: full + partner: + ageInMonths: + "$serde_json::private::Number": "36" + businessModel: business-focused + id: mvno-123 + name: TechMobile + region: Northeast + subscriberCount: + "$serde_json::private::Number": "120000" + type: premium + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + partner.ageInMonths: + "$serde_json::private::Number": "36" + partner.subscriberCount: + "$serde_json::private::Number": "120000" + partner.type: premium + rule: + _id: rule1 + "partner.ageInMonths[partnerAge]": "> 24" + "partner.subscriberCount[subscribers]": "> 100000" + "partner.type[partnerType]": "'premium'" + pricingTier: + id: pricingTier + input: + config: + bandwidthPriority: high + serviceAccessLevel: full + partner: + ageInMonths: + "$serde_json::private::Number": "36" + businessModel: business-focused + id: mvno-123 + name: TechMobile + region: Northeast + subscriberCount: + "$serde_json::private::Number": "120000" + type: premium + resources: + apiAccessLevel: advanced + dataAllocationGB: + "$serde_json::private::Number": "5000" + smsCount: + "$serde_json::private::Number": "2000000" + voiceMinutes: + "$serde_json::private::Number": "1000000" + name: partnerPricing + order: + "$serde_json::private::Number": "3" + output: + pricing: + dataRatePerMB: + "$serde_json::private::Number": "0.004" + revenueShareFactor: + "$serde_json::private::Number": "0.85" + tier: tier1 + voiceRatePerMinute: + "$serde_json::private::Number": "0.002" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + config.serviceAccessLevel: full + partner.subscriberCount: + "$serde_json::private::Number": "120000" + rule: + _id: pt1 + "config.serviceAccessLevel[i1]": "'full'" + "partner.subscriberCount[i2]": "> 100000" + resourceAllocation: + id: resourceAllocation + input: + config: + bandwidthPriority: high + serviceAccessLevel: full + partner: + ageInMonths: + "$serde_json::private::Number": "36" + businessModel: business-focused + id: mvno-123 + name: TechMobile + region: Northeast + subscriberCount: + "$serde_json::private::Number": "120000" + type: premium + name: networkResourceAllocation + order: + "$serde_json::private::Number": "2" + output: + config: + bandwidthPriority: high + serviceAccessLevel: full + partner: + ageInMonths: + "$serde_json::private::Number": "36" + businessModel: business-focused + id: mvno-123 + name: TechMobile + region: Northeast + subscriberCount: + "$serde_json::private::Number": "120000" + type: premium + resources: + apiAccessLevel: advanced + dataAllocationGB: + "$serde_json::private::Number": "5000" + smsCount: + "$serde_json::private::Number": "2000000" + voiceMinutes: + "$serde_json::private::Number": "1000000" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + config.serviceAccessLevel: full + rule: + _id: res1 + "config.serviceAccessLevel[serviceLevel]": "'full'" diff --git a/core/engine/tests/snapshots/engine__nested-request_0.snap b/core/engine/tests/snapshots/engine__nested-request_0.snap new file mode 100644 index 00000000..bd7f2faf --- /dev/null +++ b/core/engine/tests/snapshots/engine__nested-request_0.snap @@ -0,0 +1,62 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + nodeData: {} +trace: + 07f6fe29-bfcc-457f-8c84-a7594e5627e2: + id: 07f6fe29-bfcc-457f-8c84-a7594e5627e2 + input: + L1: + carbon_accounting: + score_commentary: There is likely to be + score_label: Moderate risk + name: expression3 + order: + "$serde_json::private::Number": "3" + output: + nodeData: {} + performance: "[perf]" + traceData: + nodeData: + result: "{}" + 2a8241f2-a808-4030-afd3-94ba60d93291: + id: 2a8241f2-a808-4030-afd3-94ba60d93291 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: {} + performance: "[perf]" + traceData: ~ + d0435b70-ad45-4de8-9086-2477d66344b9: + id: d0435b70-ad45-4de8-9086-2477d66344b9 + input: {} + name: expression1 + order: + "$serde_json::private::Number": "1" + output: + L1: + carbon_accounting: + score_commentary: There is likely to be + score_label: Moderate risk + performance: "[perf]" + traceData: + L1.carbon_accounting.score_commentary: + result: "\"There is likely to be\"" + L1.carbon_accounting.score_label: + result: "\"Moderate risk\"" + d438419f-c54a-49b4-b2a0-3bb626b0617f: + id: d438419f-c54a-49b4-b2a0-3bb626b0617f + input: {} + name: expression2 + order: + "$serde_json::private::Number": "2" + output: + L1: {} + performance: "[perf]" + traceData: + L1: + result: "{}" diff --git a/core/engine/tests/snapshots/engine__online-checkin-eligibility_0.snap b/core/engine/tests/snapshots/engine__online-checkin-eligibility_0.snap new file mode 100644 index 00000000..a69d5132 --- /dev/null +++ b/core/engine/tests/snapshots/engine__online-checkin-eligibility_0.snap @@ -0,0 +1,269 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + canAddBaggage: true + canSelectSeat: true + isEligible: false + message: You are eligible for online check-in. + statusCode: eligible +trace: + dt1: + id: dt1 + input: + currentTime: + "$serde_json::private::Number": "1742459400" + flight: + allowsExtraBaggage: true + departureTime: "2025-03-20T10:30:00Z" + destination: JFK + flightNumber: BA123 + hasSeatSelection: true + hasSpecialMealOptions: true + origin: LHR + requiresVisa: true + flightDepartureTime: + "$serde_json::private::Number": "1742466600" + hasRequiredDocuments: true + hoursUntilDeparture: + "$serde_json::private::Number": "2" + passenger: + frequentFlyerStatus: gold + hasValidPassport: true + hasValidVisa: true + id: P12345678 + name: John Smith + requiresSpecialAssistance: false + name: checkEligibility + order: + "$serde_json::private::Number": "2" + output: + currentTime: + "$serde_json::private::Number": "1742459400" + flight: + allowsExtraBaggage: true + departureTime: "2025-03-20T10:30:00Z" + destination: JFK + flightNumber: BA123 + hasSeatSelection: true + hasSpecialMealOptions: true + origin: LHR + requiresVisa: true + flightDepartureTime: + "$serde_json::private::Number": "1742466600" + hasRequiredDocuments: true + hoursUntilDeparture: + "$serde_json::private::Number": "2" + isEligible: true + message: You are eligible for online check-in. + passenger: + frequentFlyerStatus: gold + hasValidPassport: true + hasValidVisa: true + id: P12345678 + name: John Smith + requiresSpecialAssistance: false + statusCode: eligible + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: {} + rule: + _id: r1-4 + ex1: + id: ex1 + input: + flight: + allowsExtraBaggage: true + departureTime: "2025-03-20T10:30:00Z" + destination: JFK + flightNumber: BA123 + hasSeatSelection: true + hasSpecialMealOptions: true + origin: LHR + requiresVisa: true + passenger: + frequentFlyerStatus: gold + hasValidPassport: true + hasValidVisa: true + id: P12345678 + name: John Smith + requiresSpecialAssistance: false + name: preprocessData + order: + "$serde_json::private::Number": "1" + output: + currentTime: + "$serde_json::private::Number": "1742459400" + flight: + allowsExtraBaggage: true + departureTime: "2025-03-20T10:30:00Z" + destination: JFK + flightNumber: BA123 + hasSeatSelection: true + hasSpecialMealOptions: true + origin: LHR + requiresVisa: true + flightDepartureTime: + "$serde_json::private::Number": "1742466600" + hasRequiredDocuments: true + hoursUntilDeparture: + "$serde_json::private::Number": "2" + passenger: + frequentFlyerStatus: gold + hasValidPassport: true + hasValidVisa: true + id: P12345678 + name: John Smith + requiresSpecialAssistance: false + performance: "[perf]" + traceData: + currentTime: + result: "1742459400" + flightDepartureTime: + result: "1742466600" + hasRequiredDocuments: + result: "true" + hoursUntilDeparture: + result: "2" + ex2: + id: ex2 + input: + currentTime: + "$serde_json::private::Number": "1742459400" + flight: + allowsExtraBaggage: true + departureTime: "2025-03-20T10:30:00Z" + destination: JFK + flightNumber: BA123 + hasSeatSelection: true + hasSpecialMealOptions: true + origin: LHR + requiresVisa: true + flightDepartureTime: + "$serde_json::private::Number": "1742466600" + hasRequiredDocuments: true + hoursUntilDeparture: + "$serde_json::private::Number": "2" + isEligible: true + message: You are eligible for online check-in. + passenger: + frequentFlyerStatus: gold + hasValidPassport: true + hasValidVisa: true + id: P12345678 + name: John Smith + requiresSpecialAssistance: false + statusCode: eligible + name: additionalServices + order: + "$serde_json::private::Number": "4" + output: + canAddBaggage: true + canSelectSeat: true + isEligible: false + message: You are eligible for online check-in. + statusCode: eligible + performance: "[perf]" + traceData: + canAddBaggage: + result: "true" + canSelectSeat: + result: "true" + isEligible: + result: "false" + message: + result: "\"You are eligible for online check-in.\"" + statusCode: + result: "\"eligible\"" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + flight: + allowsExtraBaggage: true + departureTime: "2025-03-20T10:30:00Z" + destination: JFK + flightNumber: BA123 + hasSeatSelection: true + hasSpecialMealOptions: true + origin: LHR + requiresVisa: true + passenger: + frequentFlyerStatus: gold + hasValidPassport: true + hasValidVisa: true + id: P12345678 + name: John Smith + requiresSpecialAssistance: false + performance: "[perf]" + traceData: ~ + sw1: + id: sw1 + input: + currentTime: + "$serde_json::private::Number": "1742459400" + flight: + allowsExtraBaggage: true + departureTime: "2025-03-20T10:30:00Z" + destination: JFK + flightNumber: BA123 + hasSeatSelection: true + hasSpecialMealOptions: true + origin: LHR + requiresVisa: true + flightDepartureTime: + "$serde_json::private::Number": "1742466600" + hasRequiredDocuments: true + hoursUntilDeparture: + "$serde_json::private::Number": "2" + isEligible: true + message: You are eligible for online check-in. + passenger: + frequentFlyerStatus: gold + hasValidPassport: true + hasValidVisa: true + id: P12345678 + name: John Smith + requiresSpecialAssistance: false + statusCode: eligible + name: eligibilityCheck + order: + "$serde_json::private::Number": "3" + output: + currentTime: + "$serde_json::private::Number": "1742459400" + flight: + allowsExtraBaggage: true + departureTime: "2025-03-20T10:30:00Z" + destination: JFK + flightNumber: BA123 + hasSeatSelection: true + hasSpecialMealOptions: true + origin: LHR + requiresVisa: true + flightDepartureTime: + "$serde_json::private::Number": "1742466600" + hasRequiredDocuments: true + hoursUntilDeparture: + "$serde_json::private::Number": "2" + isEligible: true + message: You are eligible for online check-in. + passenger: + frequentFlyerStatus: gold + hasValidPassport: true + hasValidVisa: true + id: P12345678 + name: John Smith + requiresSpecialAssistance: false + statusCode: eligible + performance: "[perf]" + traceData: + statements: + - id: s1-1 diff --git a/core/engine/tests/snapshots/engine__order-consolidation-system_0.snap b/core/engine/tests/snapshots/engine__order-consolidation-system_0.snap new file mode 100644 index 00000000..f6723452 --- /dev/null +++ b/core/engine/tests/snapshots/engine__order-consolidation-system_0.snap @@ -0,0 +1,678 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + canConsolidate: true + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + consolidationAction: immediate_consolidation + consolidationPriority: high + consolidationWeight: + "$serde_json::private::Number": "20.7" + costSavingEstimate: + "$serde_json::private::Number": "23.75" + costSavingsReport: + fuelSavings: + "$serde_json::private::Number": "5.25" + laborSavings: + "$serde_json::private::Number": "23.75" + totalSavings: + "$serde_json::private::Number": "29" + deliverySchedule: + estimatedDeliveryTime: ~ + notificationRequired: false + type: consolidated + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + expectedFuelSavings: + "$serde_json::private::Number": "5.25" + explanation: "Orders are nearby, delivery window compatible, and carrier has capacity" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + schedulingPriority: high +trace: + dt1: + id: dt1 + input: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + name: evaluateConsolidationFactors + order: + "$serde_json::private::Number": "1" + output: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + consolidationPriority: high + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + explanation: "Orders are nearby, delivery window compatible, and carrier has capacity" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + rule: + _id: r1-1 + "availableCarrierCapacity[i1-3]": "> 3" + "deliveryWindowDifferenceHours[i1-2]": "< 48" + "distanceKm[i1-1]": "< 50" + ex1: + id: ex1 + input: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + consolidationPriority: high + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + explanation: "Orders are nearby, delivery window compatible, and carrier has capacity" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + name: calculateConsolidationMetrics + order: + "$serde_json::private::Number": "2" + output: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + canConsolidate: true + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + consolidationPriority: high + consolidationWeight: + "$serde_json::private::Number": "20.7" + costSavingEstimate: + "$serde_json::private::Number": "23.75" + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + expectedFuelSavings: + "$serde_json::private::Number": "5.25" + explanation: "Orders are nearby, delivery window compatible, and carrier has capacity" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + performance: "[perf]" + traceData: + canConsolidate: + result: "true" + consolidationWeight: + result: "20.7" + costSavingEstimate: + result: "23.75" + expectedFuelSavings: + result: "5.25" + ex2: + id: ex2 + input: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + canConsolidate: true + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + consolidationPriority: high + consolidationWeight: + "$serde_json::private::Number": "20.7" + costSavingEstimate: + "$serde_json::private::Number": "23.75" + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + expectedFuelSavings: + "$serde_json::private::Number": "5.25" + explanation: "Orders are nearby, delivery window compatible, and carrier has capacity" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + name: highPriorityProcessing + order: + "$serde_json::private::Number": "4" + output: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + canConsolidate: true + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + consolidationAction: immediate_consolidation + consolidationPriority: high + consolidationWeight: + "$serde_json::private::Number": "20.7" + costSavingEstimate: + "$serde_json::private::Number": "23.75" + costSavingsReport: + fuelSavings: + "$serde_json::private::Number": "5.25" + laborSavings: + "$serde_json::private::Number": "23.75" + totalSavings: + "$serde_json::private::Number": "29" + deliverySchedule: + estimatedDeliveryTime: ~ + notificationRequired: false + type: consolidated + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + expectedFuelSavings: + "$serde_json::private::Number": "5.25" + explanation: "Orders are nearby, delivery window compatible, and carrier has capacity" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + schedulingPriority: high + performance: "[perf]" + traceData: + consolidationAction: + result: "\"immediate_consolidation\"" + costSavingsReport: + result: "{\"fuelSavings\":5.25,\"laborSavings\":23.75,\"totalSavings\":29}" + deliverySchedule: + result: "{\"estimatedDeliveryTime\":null,\"type\":\"consolidated\",\"notificationRequired\":false}" + schedulingPriority: + result: "\"high\"" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + performance: "[perf]" + traceData: ~ + sw1: + id: sw1 + input: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + canConsolidate: true + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + consolidationPriority: high + consolidationWeight: + "$serde_json::private::Number": "20.7" + costSavingEstimate: + "$serde_json::private::Number": "23.75" + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + expectedFuelSavings: + "$serde_json::private::Number": "5.25" + explanation: "Orders are nearby, delivery window compatible, and carrier has capacity" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + name: routeByConsolidationPriority + order: + "$serde_json::private::Number": "3" + output: + availableCarrierCapacity: + "$serde_json::private::Number": "4" + canConsolidate: true + carrierDetails: + carrierId: CAR-789 + currentLoad: + "$serde_json::private::Number": "320" + maxCapacity: + "$serde_json::private::Number": "500" + consolidationPriority: high + consolidationWeight: + "$serde_json::private::Number": "20.7" + costSavingEstimate: + "$serde_json::private::Number": "23.75" + deliveryWindowDifferenceHours: + "$serde_json::private::Number": "24" + distanceKm: + "$serde_json::private::Number": "35" + expectedFuelSavings: + "$serde_json::private::Number": "5.25" + explanation: "Orders are nearby, delivery window compatible, and carrier has capacity" + orderWeight1: + "$serde_json::private::Number": "12.5" + orderWeight2: + "$serde_json::private::Number": "8.2" + orders: + - customerName: John Smith + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.7817" + longitude: + "$serde_json::private::Number": "-89.6501" + state: IL + street: 123 Main St + zipCode: "62704" + orderId: ORD-12345 + orderItems: + "$serde_json::private::Number": "3" + orderWeight: + "$serde_json::private::Number": "12.5" + requestedDeliveryDate: "2025-03-25T14:00:00Z" + - customerName: Jane Doe + deliveryAddress: + city: Springfield + coordinates: + latitude: + "$serde_json::private::Number": "39.8021" + longitude: + "$serde_json::private::Number": "-89.6443" + state: IL + street: 456 Oak Ave + zipCode: "62702" + orderId: ORD-12346 + orderItems: + "$serde_json::private::Number": "2" + orderWeight: + "$serde_json::private::Number": "8.2" + requestedDeliveryDate: "2025-03-25T16:00:00Z" + performance: "[perf]" + traceData: + statements: + - id: s1-1 diff --git a/core/engine/tests/snapshots/engine__partner-revenue-sharing_0.snap b/core/engine/tests/snapshots/engine__partner-revenue-sharing_0.snap new file mode 100644 index 00000000..d378284f --- /dev/null +++ b/core/engine/tests/snapshots/engine__partner-revenue-sharing_0.snap @@ -0,0 +1,126 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + baseCommission: + "$serde_json::private::Number": "525000" + bonusCommission: + "$serde_json::private::Number": "37950" + durationMultiplier: + "$serde_json::private::Number": "1.1" + segmentMultiplier: + "$serde_json::private::Number": "1.15" + telcoRevenue: + "$serde_json::private::Number": "937050" + totalCommission: + "$serde_json::private::Number": "562950" +trace: + dt1: + id: dt1 + input: + contractDuration: + "$serde_json::private::Number": "24" + customerSegment: enterprise + exclusivity: true + partnerType: content + revenueGenerated: + "$serde_json::private::Number": "1500000" + serviceCategory: streaming + name: partnerCommissionRates + order: + "$serde_json::private::Number": "1" + output: + baseCommissionRate: + "$serde_json::private::Number": "0.35" + bonusRate: + "$serde_json::private::Number": "0.02" + contractDuration: + "$serde_json::private::Number": "24" + customerSegment: enterprise + exclusivity: true + partnerTier: premium + partnerType: content + revenueGenerated: + "$serde_json::private::Number": "1500000" + serviceCategory: streaming + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + exclusivity: true + partnerType: content + revenueGenerated: + "$serde_json::private::Number": "1500000" + serviceCategory: streaming + rule: + _id: r1 + "exclusivity[i1-4]": "true" + "partnerType[i1-1]": "'content'" + "revenueGenerated[i1-3]": "> 1000000" + "serviceCategory[i1-2]": "'streaming'" + ex1: + id: ex1 + input: + baseCommissionRate: + "$serde_json::private::Number": "0.35" + bonusRate: + "$serde_json::private::Number": "0.02" + contractDuration: + "$serde_json::private::Number": "24" + customerSegment: enterprise + exclusivity: true + partnerTier: premium + partnerType: content + revenueGenerated: + "$serde_json::private::Number": "1500000" + serviceCategory: streaming + name: calculateCommission + order: + "$serde_json::private::Number": "2" + output: + baseCommission: + "$serde_json::private::Number": "525000" + bonusCommission: + "$serde_json::private::Number": "37950" + durationMultiplier: + "$serde_json::private::Number": "1.1" + segmentMultiplier: + "$serde_json::private::Number": "1.15" + telcoRevenue: + "$serde_json::private::Number": "937050" + totalCommission: + "$serde_json::private::Number": "562950" + performance: "[perf]" + traceData: + baseCommission: + result: "525000" + bonusCommission: + result: "37950" + durationMultiplier: + result: "1.1" + segmentMultiplier: + result: "1.15" + telcoRevenue: + result: "937050" + totalCommission: + result: "562950" + ip1: + id: ip1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + contractDuration: + "$serde_json::private::Number": "24" + customerSegment: enterprise + exclusivity: true + partnerType: content + revenueGenerated: + "$serde_json::private::Number": "1500000" + serviceCategory: streaming + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__patient-triage-system_0.snap b/core/engine/tests/snapshots/engine__patient-triage-system_0.snap new file mode 100644 index 00000000..f6f5a304 --- /dev/null +++ b/core/engine/tests/snapshots/engine__patient-triage-system_0.snap @@ -0,0 +1,281 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + highestFlag: orange + maxWaitTimeMinutes: + "$serde_json::private::Number": "10" + priorityLevel: Level 2 - Very Urgent +trace: + calculatePriority: + id: calculatePriority + input: + chiefComplaint: fracture + flags: + complaintFlag: orange + symptomFlag: orange + vitalFlag: green + scores: + complaintScore: + "$serde_json::private::Number": "20" + symptomScore: + "$serde_json::private::Number": "20" + vitalScore: + "$serde_json::private::Number": "0" + symptoms: + - moderate pain + - fever + - dizziness + vitals: + heartRate: + "$serde_json::private::Number": "115" + oxygenSaturation: + "$serde_json::private::Number": "94" + respiratoryRate: + "$serde_json::private::Number": "24" + systolicBP: + "$serde_json::private::Number": "165" + temperature: + "$serde_json::private::Number": "38.7" + name: calculate_priority_level + order: + "$serde_json::private::Number": "4" + output: + highestFlag: orange + maxWaitTimeMinutes: + "$serde_json::private::Number": "10" + priorityLevel: Level 2 - Very Urgent + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + scores.vitalScore + scores.symptomScore + scores.complaintScore: + "$serde_json::private::Number": "40" + values(flags): + - orange + - orange + - green + rule: + _id: cp3 + "scores.vitalScore + scores.symptomScore + scores.complaintScore[i2]": ">= 40" + "values(flags)[i1]": "contains($, 'orange')" + chiefComplaint: + id: chiefComplaint + input: + chiefComplaint: fracture + flags: + symptomFlag: orange + vitalFlag: green + scores: + symptomScore: + "$serde_json::private::Number": "20" + vitalScore: + "$serde_json::private::Number": "0" + symptoms: + - moderate pain + - fever + - dizziness + vitals: + heartRate: + "$serde_json::private::Number": "115" + oxygenSaturation: + "$serde_json::private::Number": "94" + respiratoryRate: + "$serde_json::private::Number": "24" + systolicBP: + "$serde_json::private::Number": "165" + temperature: + "$serde_json::private::Number": "38.7" + name: chief_complaint_assessment + order: + "$serde_json::private::Number": "3" + output: + chiefComplaint: fracture + flags: + complaintFlag: orange + symptomFlag: orange + vitalFlag: green + scores: + complaintScore: + "$serde_json::private::Number": "20" + symptomScore: + "$serde_json::private::Number": "20" + vitalScore: + "$serde_json::private::Number": "0" + symptoms: + - moderate pain + - fever + - dizziness + vitals: + heartRate: + "$serde_json::private::Number": "115" + oxygenSaturation: + "$serde_json::private::Number": "94" + respiratoryRate: + "$serde_json::private::Number": "24" + systolicBP: + "$serde_json::private::Number": "165" + temperature: + "$serde_json::private::Number": "38.7" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + chiefComplaint: fracture + rule: + _id: cc2 + "chiefComplaint[i1]": "\"fracture\", \"deep cut\", \"burn\", \"allergic reaction\", \"infection\", \"pregnancy complication\"" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + chiefComplaint: fracture + symptoms: + - moderate pain + - fever + - dizziness + vitals: + heartRate: + "$serde_json::private::Number": "115" + oxygenSaturation: + "$serde_json::private::Number": "94" + respiratoryRate: + "$serde_json::private::Number": "24" + systolicBP: + "$serde_json::private::Number": "165" + temperature: + "$serde_json::private::Number": "38.7" + performance: "[perf]" + traceData: ~ + symptoms: + id: symptoms + input: + chiefComplaint: fracture + flags: + vitalFlag: green + scores: + vitalScore: + "$serde_json::private::Number": "0" + symptoms: + - moderate pain + - fever + - dizziness + vitals: + heartRate: + "$serde_json::private::Number": "115" + oxygenSaturation: + "$serde_json::private::Number": "94" + respiratoryRate: + "$serde_json::private::Number": "24" + systolicBP: + "$serde_json::private::Number": "165" + temperature: + "$serde_json::private::Number": "38.7" + name: symptom_assessment + order: + "$serde_json::private::Number": "2" + output: + chiefComplaint: fracture + flags: + symptomFlag: orange + vitalFlag: green + scores: + symptomScore: + "$serde_json::private::Number": "20" + vitalScore: + "$serde_json::private::Number": "0" + symptoms: + - moderate pain + - fever + - dizziness + vitals: + heartRate: + "$serde_json::private::Number": "115" + oxygenSaturation: + "$serde_json::private::Number": "94" + respiratoryRate: + "$serde_json::private::Number": "24" + systolicBP: + "$serde_json::private::Number": "165" + temperature: + "$serde_json::private::Number": "38.7" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: sym2 + vitalSigns: + id: vitalSigns + input: + chiefComplaint: fracture + symptoms: + - moderate pain + - fever + - dizziness + vitals: + heartRate: + "$serde_json::private::Number": "115" + oxygenSaturation: + "$serde_json::private::Number": "94" + respiratoryRate: + "$serde_json::private::Number": "24" + systolicBP: + "$serde_json::private::Number": "165" + temperature: + "$serde_json::private::Number": "38.7" + name: vital_signs_assessment + order: + "$serde_json::private::Number": "1" + output: + chiefComplaint: fracture + flags: + vitalFlag: green + scores: + vitalScore: + "$serde_json::private::Number": "0" + symptoms: + - moderate pain + - fever + - dizziness + vitals: + heartRate: + "$serde_json::private::Number": "115" + oxygenSaturation: + "$serde_json::private::Number": "94" + respiratoryRate: + "$serde_json::private::Number": "24" + systolicBP: + "$serde_json::private::Number": "165" + temperature: + "$serde_json::private::Number": "38.7" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + vitals.heartRate: + "$serde_json::private::Number": "115" + vitals.oxygenSaturation: + "$serde_json::private::Number": "94" + vitals.respiratoryRate: + "$serde_json::private::Number": "24" + vitals.systolicBP: + "$serde_json::private::Number": "165" + vitals.temperature: + "$serde_json::private::Number": "38.7" + rule: + _id: vs4 + "vitals.heartRate[i2]": "" + "vitals.oxygenSaturation[i5]": "" + "vitals.respiratoryRate[i3]": "" + "vitals.systolicBP[i4]": "" + "vitals.temperature[i1]": "" diff --git a/core/engine/tests/snapshots/engine__payment-routing-and-fee-calculator_0.snap b/core/engine/tests/snapshots/engine__payment-routing-and-fee-calculator_0.snap new file mode 100644 index 00000000..3772bdd2 --- /dev/null +++ b/core/engine/tests/snapshots/engine__payment-routing-and-fee-calculator_0.snap @@ -0,0 +1,584 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + routing: + processing_instructions: + fraud_scan: standard + manual_review: true + priority: medium + processor: credit_processor + velocity_check: true + verification_required: 3ds + security: + fraud_scan_level: standard + high_risk_flag: true + total_risk_score: + "$serde_json::private::Number": "50" + velocity_check_required: true +trace: + amount-processing: + id: amount-processing + input: + fee: + base_percentage: + "$serde_json::private::Number": "2.9" + channel_addition: + "$serde_json::private::Number": "0.3" + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + routing: + priority: medium + processor: credit_processor + security: + base_risk_score: + "$serde_json::private::Number": "25" + channel_risk_addition: + "$serde_json::private::Number": "5" + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + name: amount-based-processing + order: + "$serde_json::private::Number": "3" + output: + fee: + amount_adjustment: + "$serde_json::private::Number": "-0.3" + base_percentage: + "$serde_json::private::Number": "2.9" + channel_addition: + "$serde_json::private::Number": "0.3" + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + routing: + priority: medium + processor: credit_processor + security: + amount_risk_addition: + "$serde_json::private::Number": "20" + base_risk_score: + "$serde_json::private::Number": "25" + channel_risk_addition: + "$serde_json::private::Number": "5" + verification_method: 3ds + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + payment.amount: + "$serde_json::private::Number": "2500" + routing.processor: credit_processor + rule: + _id: rule-medium-high-amount + "payment.amount[input-amount]": ">= 5000, < 10000" + "routing.processor[input-route]": "" + channel-routing-table: + id: channel-routing-table + input: + fee: + base_percentage: + "$serde_json::private::Number": "2.9" + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + routing: + processor: credit_processor + security: + base_risk_score: + "$serde_json::private::Number": "25" + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + name: channel-routing + order: + "$serde_json::private::Number": "2" + output: + fee: + base_percentage: + "$serde_json::private::Number": "2.9" + channel_addition: + "$serde_json::private::Number": "0.3" + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + routing: + priority: medium + processor: credit_processor + security: + base_risk_score: + "$serde_json::private::Number": "25" + channel_risk_addition: + "$serde_json::private::Number": "5" + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + payment.channel: web + security.base_risk_score: + "$serde_json::private::Number": "25" + rule: + _id: rule-web-low-risk + "payment.channel[input-channel]": "'web'" + "security.base_risk_score[input-risk-score]": "<= 30" + fee-calculation: + id: fee-calculation + input: + fee: + amount_adjustment: + "$serde_json::private::Number": "-0.3" + base_percentage: + "$serde_json::private::Number": "2.9" + channel_addition: + "$serde_json::private::Number": "0.3" + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + routing: + priority: medium + processor: credit_processor + security: + amount_risk_addition: + "$serde_json::private::Number": "20" + base_risk_score: + "$serde_json::private::Number": "25" + channel_risk_addition: + "$serde_json::private::Number": "5" + verification_method: 3ds + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + name: fee-calculation + order: + "$serde_json::private::Number": "4" + output: + fee: + amount_adjustment: + "$serde_json::private::Number": "-0.3" + base_percentage: + "$serde_json::private::Number": "2.9" + channel_addition: + "$serde_json::private::Number": "0.3" + final_amount: + "$serde_json::private::Number": "72.5" + fee_amount: + "$serde_json::private::Number": "72.5" + final_fee_percentage: + "$serde_json::private::Number": "2.9" + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + net_amount: + "$serde_json::private::Number": "2427.5" + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + routing: + priority: medium + processor: credit_processor + security: + amount_risk_addition: + "$serde_json::private::Number": "20" + base_risk_score: + "$serde_json::private::Number": "25" + channel_risk_addition: + "$serde_json::private::Number": "5" + verification_method: 3ds + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + performance: "[perf]" + traceData: + fee.final_amount: + result: "72.5" + fee_amount: + result: "72.5" + final_fee_percentage: + result: "2.9" + payment.net_amount: + result: "2427.5" + payment-input: + id: payment-input + input: ~ + name: payment-request + order: + "$serde_json::private::Number": "0" + output: + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + performance: "[perf]" + traceData: ~ + payment-type-table: + id: payment-type-table + input: + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + name: payment-type-processing + order: + "$serde_json::private::Number": "1" + output: + fee: + base_percentage: + "$serde_json::private::Number": "2.9" + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + routing: + processor: credit_processor + security: + base_risk_score: + "$serde_json::private::Number": "25" + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + payment.type: credit_card + rule: + _id: rule-credit-card + "payment.type[input-payment-type]": "'credit_card'" + security-requirements: + id: security-requirements + input: + fee: + amount_adjustment: + "$serde_json::private::Number": "-0.3" + base_percentage: + "$serde_json::private::Number": "2.9" + channel_addition: + "$serde_json::private::Number": "0.3" + final_amount: + "$serde_json::private::Number": "72.5" + fee_amount: + "$serde_json::private::Number": "72.5" + final_fee_percentage: + "$serde_json::private::Number": "2.9" + merchant: + category: retail + country: US + id: merch_98765432 + processing_history: + average_amount: + "$serde_json::private::Number": "175.5" + chargeback_rate: + "$serde_json::private::Number": "0.2" + total_transactions: + "$serde_json::private::Number": "1256" + payment: + amount: + "$serde_json::private::Number": "2500" + channel: web + currency: USD + customer_id: cust_87654321 + id: pmt_12345678 + metadata: + card_last_four: "4242" + card_network: Visa + save_for_future: true + net_amount: + "$serde_json::private::Number": "2427.5" + timestamp: "2025-03-18T10:30:45Z" + type: credit_card + routing: + priority: medium + processor: credit_processor + security: + amount_risk_addition: + "$serde_json::private::Number": "20" + base_risk_score: + "$serde_json::private::Number": "25" + channel_risk_addition: + "$serde_json::private::Number": "5" + verification_method: 3ds + session: + browser: Chrome + device_id: dev_abcdef123456 + ip_address: 192.168.1.1 + location: + city: San Francisco + country: US + state: CA + name: security-verification + order: + "$serde_json::private::Number": "5" + output: + routing: + processing_instructions: + fraud_scan: standard + manual_review: true + priority: medium + processor: credit_processor + velocity_check: true + verification_required: 3ds + security: + fraud_scan_level: standard + high_risk_flag: true + total_risk_score: + "$serde_json::private::Number": "50" + velocity_check_required: true + performance: "[perf]" + traceData: + routing.processing_instructions: + result: "{\"priority\":\"medium\",\"velocity_check\":true,\"fraud_scan\":\"standard\",\"manual_review\":true,\"verification_required\":\"3ds\",\"processor\":\"credit_processor\"}" + security.fraud_scan_level: + result: "\"standard\"" + security.high_risk_flag: + result: "true" + security.total_risk_score: + result: "50" + security.velocity_check_required: + result: "true" diff --git a/core/engine/tests/snapshots/engine__policy-discount-calculator_0.snap b/core/engine/tests/snapshots/engine__policy-discount-calculator_0.snap new file mode 100644 index 00000000..7fd89e66 --- /dev/null +++ b/core/engine/tests/snapshots/engine__policy-discount-calculator_0.snap @@ -0,0 +1,346 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + discounts: + bundle: + description: Dual policy discount + percentage: + "$serde_json::private::Number": "7" + loyalty: + description: Standard loyalty discount + percentage: + "$serde_json::private::Number": "10" + safetyFeatures: + - description: Anti-theft system discount + percentage: + "$serde_json::private::Number": "3" + - description: ADAS discount + percentage: + "$serde_json::private::Number": "5" + finalPremium: + "$serde_json::private::Number": "900" + maximumDiscountPercentage: + "$serde_json::private::Number": "25" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + totalDiscountPercentage: + "$serde_json::private::Number": "25" +trace: + bundledPoliciesTable: + id: bundledPoliciesTable + input: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + discounts: + loyalty: + description: Standard loyalty discount + percentage: + "$serde_json::private::Number": "10" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + name: bundledPoliciesDiscounts + order: + "$serde_json::private::Number": "2" + output: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + discounts: + bundle: + description: Dual policy discount + percentage: + "$serde_json::private::Number": "7" + loyalty: + description: Standard loyalty discount + percentage: + "$serde_json::private::Number": "10" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + customer.numberOfPolicies: + "$serde_json::private::Number": "2" + rule: + _id: r2-2 + "customer.numberOfPolicies[i2-1]": "2" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + performance: "[perf]" + traceData: ~ + loyaltyDiscountsTable: + id: loyaltyDiscountsTable + input: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + name: customerLoyaltyDiscounts + order: + "$serde_json::private::Number": "1" + output: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + discounts: + loyalty: + description: Standard loyalty discount + percentage: + "$serde_json::private::Number": "10" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + customer.yearsAsCustomer: + "$serde_json::private::Number": "4" + rule: + _id: r1-2 + "customer.yearsAsCustomer[i1-1]": ">= 3" + safetyFeaturesTable: + id: safetyFeaturesTable + input: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + discounts: + bundle: + description: Dual policy discount + percentage: + "$serde_json::private::Number": "7" + loyalty: + description: Standard loyalty discount + percentage: + "$serde_json::private::Number": "10" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + name: safetyFeaturesDiscounts + order: + "$serde_json::private::Number": "3" + output: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + discounts: + bundle: + description: Dual policy discount + percentage: + "$serde_json::private::Number": "7" + loyalty: + description: Standard loyalty discount + percentage: + "$serde_json::private::Number": "10" + safetyFeatures: + - description: Anti-theft system discount + percentage: + "$serde_json::private::Number": "3" + - description: ADAS discount + percentage: + "$serde_json::private::Number": "5" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: + policy.safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + rule: + _id: r3-1 + "policy.safetyFeatures[i3-1]": "contains($, 'antiTheftSystem')" + - index: + "$serde_json::private::Number": "2" + reference_map: + policy.safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + rule: + _id: r3-3 + "policy.safetyFeatures[i3-1]": "contains($, 'advancedDriverAssistance')" + totalDiscountCalculation: + id: totalDiscountCalculation + input: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + discounts: + bundle: + description: Dual policy discount + percentage: + "$serde_json::private::Number": "7" + loyalty: + description: Standard loyalty discount + percentage: + "$serde_json::private::Number": "10" + safetyFeatures: + - description: Anti-theft system discount + percentage: + "$serde_json::private::Number": "3" + - description: ADAS discount + percentage: + "$serde_json::private::Number": "5" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + name: calculateTotalDiscount + order: + "$serde_json::private::Number": "4" + output: + customer: + id: C12345 + name: Jane Smith + numberOfPolicies: + "$serde_json::private::Number": "2" + yearsAsCustomer: + "$serde_json::private::Number": "4" + discounts: + bundle: + description: Dual policy discount + percentage: + "$serde_json::private::Number": "7" + loyalty: + description: Standard loyalty discount + percentage: + "$serde_json::private::Number": "10" + safetyFeatures: + - description: Anti-theft system discount + percentage: + "$serde_json::private::Number": "3" + - description: ADAS discount + percentage: + "$serde_json::private::Number": "5" + finalPremium: + "$serde_json::private::Number": "900" + maximumDiscountPercentage: + "$serde_json::private::Number": "25" + policy: + basePremium: + "$serde_json::private::Number": "1200" + id: P98765 + safetyFeatures: + - antiTheftSystem + - advancedDriverAssistance + type: auto + totalDiscountPercentage: + "$serde_json::private::Number": "25" + performance: "[perf]" + traceData: + finalPremium: + result: "900" + maximumDiscountPercentage: + result: "25" + totalDiscountPercentage: + result: "25" diff --git a/core/engine/tests/snapshots/engine__policy-eligibility-analyzer_0.snap b/core/engine/tests/snapshots/engine__policy-eligibility-analyzer_0.snap new file mode 100644 index 00000000..9b507f14 --- /dev/null +++ b/core/engine/tests/snapshots/engine__policy-eligibility-analyzer_0.snap @@ -0,0 +1,303 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + denialReasons: [] + eligibility: + age: + isEligible: true + reason: Age requirements met + location: + isEligible: true + reason: Location requirements met + riskFactors: + isEligible: true + reason: Risk factor assessment passed + isEligible: true + policyDecision: + approved: ~ + reasons: ~ +trace: + ageEligibility: + id: ageEligibility + input: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + name: Age Eligibility + order: + "$serde_json::private::Number": "1" + output: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + eligibility: + age: + isEligible: true + reason: Age requirements met + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + customer.age: + "$serde_json::private::Number": "45" + rule: + _id: rule3 + "customer.age[i1-1]": "" + finalDetermination: + id: finalDetermination + input: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + eligibility: + age: + isEligible: true + reason: Age requirements met + location: + isEligible: true + reason: Location requirements met + riskFactors: + isEligible: true + reason: Risk factor assessment passed + name: Final Determination + order: + "$serde_json::private::Number": "4" + output: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + denialReasons: [] + eligibility: + age: + isEligible: true + reason: Age requirements met + location: + isEligible: true + reason: Location requirements met + riskFactors: + isEligible: true + reason: Risk factor assessment passed + isEligible: true + policyDecision: + approved: ~ + reasons: ~ + performance: "[perf]" + traceData: + denialReasons: + result: "[]" + isEligible: + result: "true" + policyDecision: + result: "{\"reasons\":null,\"approved\":null}" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + performance: "[perf]" + traceData: ~ + locationEligibility: + id: locationEligibility + input: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + eligibility: + age: + isEligible: true + reason: Age requirements met + name: Location Eligibility + order: + "$serde_json::private::Number": "2" + output: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + eligibility: + age: + isEligible: true + reason: Age requirements met + location: + isEligible: true + reason: Location requirements met + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + customer.location.state: CA + rule: + _id: rule3 + "customer.location.state[i1-1]": "" + riskFactors: + id: riskFactors + input: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + eligibility: + age: + isEligible: true + reason: Age requirements met + location: + isEligible: true + reason: Location requirements met + name: Risk Factor Assessment + order: + "$serde_json::private::Number": "3" + output: + customer: + age: + "$serde_json::private::Number": "45" + healthScore: + "$serde_json::private::Number": "85" + location: + city: San Francisco + country: US + state: CA + riskFactors: + count: + "$serde_json::private::Number": "2" + factors: + - previous_claim + - family_history + eligibility: + age: + isEligible: true + reason: Age requirements met + location: + isEligible: true + reason: Location requirements met + riskFactors: + isEligible: true + reason: Risk factor assessment passed + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + customer.riskFactors.count: + "$serde_json::private::Number": "2" + rule: + _id: rule3 + "customer.riskFactors.count[i1-1]": "" diff --git a/core/engine/tests/snapshots/engine__portfolio-risk-monitor_0.snap b/core/engine/tests/snapshots/engine__portfolio-risk-monitor_0.snap new file mode 100644 index 00000000..9a57fd53 --- /dev/null +++ b/core/engine/tests/snapshots/engine__portfolio-risk-monitor_0.snap @@ -0,0 +1,1415 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + action: rebalance + outcome: + riskScore: + "$serde_json::private::Number": "0.53" + status: rebalance_suggested + timestamp: "2025-08-20T09:43:13.406Z" + rebalanceDetails: + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + customerId: cust-78945 + date: 2025-08-20 + driftPercentage: "5.0" + message: "Rebalancing recommended: Portfolio has drifted 5.0% from target allocation." + portfolioId: port-12345 + riskCategory: high + riskScore: + "$serde_json::private::Number": "0.53" + suggestedChanges: + bonds: + "$serde_json::private::Number": "10" + cash: + "$serde_json::private::Number": "-5" + equity: + "$serde_json::private::Number": "-5" + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" +trace: + actionDeterminationSwitch: + id: actionDeterminationSwitch + input: + assessment: + exposureFactor: + "$serde_json::private::Number": "0.5" + exposureLevel: elevated + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + volatilityFactor: + "$serde_json::private::Number": "0.4" + volatilityLevel: moderate + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + exposureWeight: + "$serde_json::private::Number": "0.4" + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + marketWeight: + "$serde_json::private::Number": "0.3" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + portfolioDrift: + "$serde_json::private::Number": "5" + riskCategory: high + riskScore: + "$serde_json::private::Number": "0.53" + volatilityWeight: + "$serde_json::private::Number": "0.3" + name: determineAction + order: + "$serde_json::private::Number": "5" + output: + assessment: + exposureFactor: + "$serde_json::private::Number": "0.5" + exposureLevel: elevated + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + volatilityFactor: + "$serde_json::private::Number": "0.4" + volatilityLevel: moderate + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + exposureWeight: + "$serde_json::private::Number": "0.4" + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + marketWeight: + "$serde_json::private::Number": "0.3" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + portfolioDrift: + "$serde_json::private::Number": "5" + riskCategory: high + riskScore: + "$serde_json::private::Number": "0.53" + volatilityWeight: + "$serde_json::private::Number": "0.3" + performance: "[perf]" + traceData: + statements: + - id: rebalanceAction + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + performance: "[perf]" + traceData: ~ + marketConditionsTable: + id: marketConditionsTable + input: + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + name: marketConditionsAssessment + order: + "$serde_json::private::Number": "1" + output: + assessment: + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + market.trendPercentage: + "$serde_json::private::Number": "-12.5" + market.volatilityIndex: + "$serde_json::private::Number": "28.5" + rule: + _id: rule2 + "market.trendPercentage[i1-2]": "< -10" + "market.volatilityIndex[i1-1]": "> 25" + portfolioExposureTable: + id: portfolioExposureTable + input: + assessment: + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + name: portfolioExposureAssessment + order: + "$serde_json::private::Number": "2" + output: + assessment: + exposureFactor: + "$serde_json::private::Number": "0.5" + exposureLevel: elevated + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + portfolio.highRiskPercentage: + "$serde_json::private::Number": "35" + rule: + _id: rule3 + "portfolio.highRiskPercentage[i1-1]": "> 30" + portfolioVolatilityTable: + id: portfolioVolatilityTable + input: + assessment: + exposureFactor: + "$serde_json::private::Number": "0.5" + exposureLevel: elevated + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + name: portfolioVolatilityAssessment + order: + "$serde_json::private::Number": "3" + output: + assessment: + exposureFactor: + "$serde_json::private::Number": "0.5" + exposureLevel: elevated + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + volatilityFactor: + "$serde_json::private::Number": "0.4" + volatilityLevel: moderate + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + assessment.marketRiskFactor: + "$serde_json::private::Number": "0.7" + portfolio.volatility: + "$serde_json::private::Number": "22.5" + rule: + _id: rule3 + "assessment.marketRiskFactor[i1-2]": "" + "portfolio.volatility[i1-1]": "> 20" + rebalanceFunction: + id: rebalanceFunction + input: + assessment: + exposureFactor: + "$serde_json::private::Number": "0.5" + exposureLevel: elevated + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + volatilityFactor: + "$serde_json::private::Number": "0.4" + volatilityLevel: moderate + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + exposureWeight: + "$serde_json::private::Number": "0.4" + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + marketWeight: + "$serde_json::private::Number": "0.3" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + portfolioDrift: + "$serde_json::private::Number": "5" + riskCategory: high + riskScore: + "$serde_json::private::Number": "0.53" + volatilityWeight: + "$serde_json::private::Number": "0.3" + name: suggestRebalancing + order: + "$serde_json::private::Number": "6" + output: + action: rebalance + outcome: + riskScore: + "$serde_json::private::Number": "0.53" + status: rebalance_suggested + timestamp: "2025-08-20T09:43:13.406Z" + rebalanceDetails: + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + customerId: cust-78945 + date: 2025-08-20 + driftPercentage: "5.0" + message: "Rebalancing recommended: Portfolio has drifted 5.0% from target allocation." + portfolioId: port-12345 + riskCategory: high + riskScore: + "$serde_json::private::Number": "0.53" + suggestedChanges: + bonds: + "$serde_json::private::Number": "10" + cash: + "$serde_json::private::Number": "-5" + equity: + "$serde_json::private::Number": "-5" + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + performance: "[perf]" + traceData: + log: [] + riskScoreCalculation: + id: riskScoreCalculation + input: + assessment: + exposureFactor: + "$serde_json::private::Number": "0.5" + exposureLevel: elevated + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + volatilityFactor: + "$serde_json::private::Number": "0.4" + volatilityLevel: moderate + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + name: calculateRiskScore + order: + "$serde_json::private::Number": "4" + output: + assessment: + exposureFactor: + "$serde_json::private::Number": "0.5" + exposureLevel: elevated + marketAssessment: Elevated volatility with substantial market decline + marketCondition: high + marketRiskFactor: + "$serde_json::private::Number": "0.7" + volatilityFactor: + "$serde_json::private::Number": "0.4" + volatilityLevel: moderate + customer: + id: cust-78945 + investmentHorizon: long-term + name: John Smith + preferences: + alertThreshold: moderate + allowAutomaticAdjustments: true + communicationPreference: email + riskTolerance: moderate + exposureWeight: + "$serde_json::private::Number": "0.4" + market: + economicIndicators: + gdpGrowth: + "$serde_json::private::Number": "0.8" + inflation: + "$serde_json::private::Number": "4.2" + unemploymentRate: + "$serde_json::private::Number": "4.1" + interestRate: + "$serde_json::private::Number": "3.75" + sectorPerformance: + consumerStaples: + "$serde_json::private::Number": "-3.2" + financials: + "$serde_json::private::Number": "-18.4" + healthcare: + "$serde_json::private::Number": "-5.1" + technology: + "$serde_json::private::Number": "-15.2" + utilities: + "$serde_json::private::Number": "1.5" + trendPercentage: + "$serde_json::private::Number": "-12.5" + volatilityIndex: + "$serde_json::private::Number": "28.5" + marketWeight: + "$serde_json::private::Number": "0.3" + portfolio: + creationDate: 2019-05-12 + currentAllocation: + bonds: + "$serde_json::private::Number": "25" + cash: + "$serde_json::private::Number": "10" + equity: + "$serde_json::private::Number": "65" + highRiskPercentage: + "$serde_json::private::Number": "35" + holdings: + - category: equity + percentage: + "$serde_json::private::Number": "30" + symbol: VTI + value: + "$serde_json::private::Number": "225000" + - category: equity + percentage: + "$serde_json::private::Number": "20" + symbol: VXUS + value: + "$serde_json::private::Number": "150000" + - category: equity + percentage: + "$serde_json::private::Number": "15" + symbol: VGT + value: + "$serde_json::private::Number": "112500" + - category: bonds + percentage: + "$serde_json::private::Number": "25" + symbol: BND + value: + "$serde_json::private::Number": "187500" + - category: cash + percentage: + "$serde_json::private::Number": "10" + symbol: CASH + value: + "$serde_json::private::Number": "75000" + id: port-12345 + lastRebalance: + "$serde_json::private::Number": "95" + name: Retirement Portfolio + targetAllocation: + bonds: + "$serde_json::private::Number": "35" + cash: + "$serde_json::private::Number": "5" + equity: + "$serde_json::private::Number": "60" + totalValue: + "$serde_json::private::Number": "750000" + volatility: + "$serde_json::private::Number": "22.5" + portfolioDrift: + "$serde_json::private::Number": "5" + riskCategory: high + riskScore: + "$serde_json::private::Number": "0.53" + volatilityWeight: + "$serde_json::private::Number": "0.3" + performance: "[perf]" + traceData: + exposureWeight: + result: "0.4" + marketWeight: + result: "0.3" + portfolioDrift: + result: "5" + riskCategory: + result: "\"high\"" + riskScore: + result: "0.53" + volatilityWeight: + result: "0.3" diff --git a/core/engine/tests/snapshots/engine__preventive-care-recommendation_0.snap b/core/engine/tests/snapshots/engine__preventive-care-recommendation_0.snap new file mode 100644 index 00000000..87c8dd4e --- /dev/null +++ b/core/engine/tests/snapshots/engine__preventive-care-recommendation_0.snap @@ -0,0 +1,298 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + patientName: Jane Smith + recommendationDate: "2025-08-20 09:43:15" + summarizedRecommendations: + - riskBasedRecommendations: Earlier and more frequent diabetes screening + - riskBasedRecommendations: Earlier and more frequent mammograms + - riskBasedRecommendations: Lung cancer screening + - ageBasedRecommendations: + primary: Blood pressure screening + quaternary: Eye exam every 2-4 years + secondary: Cholesterol screening every 5 years + tertiary: Diabetes screening every 3 years + - genderBasedRecommendations: + primary: Mammogram every 1-2 years (discuss with doctor) + secondary: Cervical cancer screening every 3 years + totalRecommendations: + "$serde_json::private::Number": "5" +trace: + ageSpecificScreenings: + id: ageSpecificScreenings + input: + age: + "$serde_json::private::Number": "42" + familyHistory: + - breast cancer + - diabetes + firstName: Jane + lastCheckup: 2023-10-15 + lastName: Smith + riskFactors: + - smoking + sex: female + name: ageBasedRecommendations + order: + "$serde_json::private::Number": "1" + output: + age: + "$serde_json::private::Number": "42" + familyHistory: + - breast cancer + - diabetes + firstName: Jane + lastCheckup: 2023-10-15 + lastName: Smith + recommendations: + age: + - recommendations: + ageBasedRecommendations: + primary: Blood pressure screening + quaternary: Eye exam every 2-4 years + secondary: Cholesterol screening every 5 years + tertiary: Diabetes screening every 3 years + riskFactors: + - smoking + sex: female + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "2" + reference_map: + age: + "$serde_json::private::Number": "42" + rule: + _id: age3 + "age[i1]": ">= 40 and < 50" + genderSpecificScreenings: + id: genderSpecificScreenings + input: + age: + "$serde_json::private::Number": "42" + familyHistory: + - breast cancer + - diabetes + firstName: Jane + lastCheckup: 2023-10-15 + lastName: Smith + recommendations: + age: + - recommendations: + ageBasedRecommendations: + primary: Blood pressure screening + quaternary: Eye exam every 2-4 years + secondary: Cholesterol screening every 5 years + tertiary: Diabetes screening every 3 years + riskFactors: + - smoking + sex: female + name: sexBasedRecommendations + order: + "$serde_json::private::Number": "2" + output: + age: + "$serde_json::private::Number": "42" + familyHistory: + - breast cancer + - diabetes + firstName: Jane + lastCheckup: 2023-10-15 + lastName: Smith + recommendations: + age: + - recommendations: + ageBasedRecommendations: + primary: Blood pressure screening + quaternary: Eye exam every 2-4 years + secondary: Cholesterol screening every 5 years + tertiary: Diabetes screening every 3 years + sex: + - recommendations: + genderBasedRecommendations: + primary: Mammogram every 1-2 years (discuss with doctor) + secondary: Cervical cancer screening every 3 years + riskFactors: + - smoking + sex: female + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "2" + reference_map: + age: + "$serde_json::private::Number": "42" + sex: female + rule: + _id: gender3 + "age[i2]": "[40..50)" + "sex[i1]": "'female'" + generateRecommendations: + id: generateRecommendations + input: + age: + "$serde_json::private::Number": "42" + familyHistory: + - breast cancer + - diabetes + firstName: Jane + lastCheckup: 2023-10-15 + lastName: Smith + recommendations: + age: + - recommendations: + ageBasedRecommendations: + primary: Blood pressure screening + quaternary: Eye exam every 2-4 years + secondary: Cholesterol screening every 5 years + tertiary: Diabetes screening every 3 years + risk: + - recommendations: + riskBasedRecommendations: Earlier and more frequent diabetes screening + - recommendations: + riskBasedRecommendations: Earlier and more frequent mammograms + - recommendations: + riskBasedRecommendations: Lung cancer screening + sex: + - recommendations: + genderBasedRecommendations: + primary: Mammogram every 1-2 years (discuss with doctor) + secondary: Cervical cancer screening every 3 years + riskFactors: + - smoking + sex: female + name: finalRecommendations + order: + "$serde_json::private::Number": "4" + output: + patientName: Jane Smith + recommendationDate: "2025-08-20 09:43:15" + summarizedRecommendations: + - riskBasedRecommendations: Earlier and more frequent diabetes screening + - riskBasedRecommendations: Earlier and more frequent mammograms + - riskBasedRecommendations: Lung cancer screening + - ageBasedRecommendations: + primary: Blood pressure screening + quaternary: Eye exam every 2-4 years + secondary: Cholesterol screening every 5 years + tertiary: Diabetes screening every 3 years + - genderBasedRecommendations: + primary: Mammogram every 1-2 years (discuss with doctor) + secondary: Cervical cancer screening every 3 years + testResults: ~ + totalRecommendations: + "$serde_json::private::Number": "5" + performance: "[perf]" + traceData: + patientName: + result: "\"Jane Smith\"" + recommendationDate: + result: "\"2025-08-20 09:43:15\"" + summarizedRecommendations: + result: "[{\"riskBasedRecommendations\":\"Earlier and more frequent diabetes screening\"},{\"riskBasedRecommendations\":\"Earlier and more frequent mammograms\"},{\"riskBasedRecommendations\":\"Lung cancer screening\"},{\"ageBasedRecommendations\":{\"tertiary\":\"Diabetes screening every 3 years\",\"primary\":\"Blood pressure screening\",\"quaternary\":\"Eye exam every 2-4 years\",\"secondary\":\"Cholesterol screening every 5 years\"}},{\"genderBasedRecommendations\":{\"secondary\":\"Cervical cancer screening every 3 years\",\"primary\":\"Mammogram every 1-2 years (discuss with doctor)\"}}]" + testResults: + result: "null" + totalRecommendations: + result: "5" + input: + id: input + input: ~ + name: patientData + order: + "$serde_json::private::Number": "0" + output: + age: + "$serde_json::private::Number": "42" + familyHistory: + - breast cancer + - diabetes + firstName: Jane + lastCheckup: 2023-10-15 + lastName: Smith + riskFactors: + - smoking + sex: female + performance: "[perf]" + traceData: ~ + riskFactorScreenings: + id: riskFactorScreenings + input: + age: + "$serde_json::private::Number": "42" + familyHistory: + - breast cancer + - diabetes + firstName: Jane + lastCheckup: 2023-10-15 + lastName: Smith + recommendations: + age: + - recommendations: + ageBasedRecommendations: + primary: Blood pressure screening + quaternary: Eye exam every 2-4 years + secondary: Cholesterol screening every 5 years + tertiary: Diabetes screening every 3 years + sex: + - recommendations: + genderBasedRecommendations: + primary: Mammogram every 1-2 years (discuss with doctor) + secondary: Cervical cancer screening every 3 years + riskFactors: + - smoking + sex: female + name: riskBasedRecommendations + order: + "$serde_json::private::Number": "3" + output: + age: + "$serde_json::private::Number": "42" + familyHistory: + - breast cancer + - diabetes + firstName: Jane + lastCheckup: 2023-10-15 + lastName: Smith + recommendations: + age: + - recommendations: + ageBasedRecommendations: + primary: Blood pressure screening + quaternary: Eye exam every 2-4 years + secondary: Cholesterol screening every 5 years + tertiary: Diabetes screening every 3 years + risk: + - recommendations: + riskBasedRecommendations: Earlier and more frequent diabetes screening + - recommendations: + riskBasedRecommendations: Earlier and more frequent mammograms + - recommendations: + riskBasedRecommendations: Lung cancer screening + sex: + - recommendations: + genderBasedRecommendations: + primary: Mammogram every 1-2 years (discuss with doctor) + secondary: Cervical cancer screening every 3 years + riskFactors: + - smoking + sex: female + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: risk1 + - index: + "$serde_json::private::Number": "3" + reference_map: {} + rule: + _id: risk4 + - index: + "$serde_json::private::Number": "4" + reference_map: {} + rule: + _id: risk5 diff --git a/core/engine/tests/snapshots/engine__product-listing-scoring_0.snap b/core/engine/tests/snapshots/engine__product-listing-scoring_0.snap new file mode 100644 index 00000000..5c473e2d --- /dev/null +++ b/core/engine/tests/snapshots/engine__product-listing-scoring_0.snap @@ -0,0 +1,308 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breakdown: + descriptionCompleteness: + category: good + score: + "$serde_json::private::Number": "25" + imageQuality: + category: good + score: + "$serde_json::private::Number": "25" + inventoryAvailability: + score: + "$serde_json::private::Number": "8" + keywordOptimization: + score: + "$serde_json::private::Number": "15" + pricingCompetitiveness: + score: + "$serde_json::private::Number": "8" + maximumPossibleScore: + "$serde_json::private::Number": "100" + overallScoreCategory: excellent + totalScore: + "$serde_json::private::Number": "81" +trace: + description-node: + id: description-node + input: + listing: + description: + hasBulletPoints: true + hasSpecifications: true + keywordDensity: + "$serde_json::private::Number": "3.2" + wordCount: + "$serde_json::private::Number": "250" + images: + count: + "$serde_json::private::Number": "4" + hasVariantImages: true + highResolution: true + inventory: + daysToShip: + "$serde_json::private::Number": "2" + stockLevel: + "$serde_json::private::Number": "15" + pricing: + competitiveRank: + "$serde_json::private::Number": "2" + hasDiscount: true + scores: + imageQuality: + category: good + score: + "$serde_json::private::Number": "25" + name: descriptionAndOtherFactors + order: + "$serde_json::private::Number": "2" + output: + listing: + description: + hasBulletPoints: true + hasSpecifications: true + keywordDensity: + "$serde_json::private::Number": "3.2" + wordCount: + "$serde_json::private::Number": "250" + images: + count: + "$serde_json::private::Number": "4" + hasVariantImages: true + highResolution: true + inventory: + daysToShip: + "$serde_json::private::Number": "2" + stockLevel: + "$serde_json::private::Number": "15" + pricing: + competitiveRank: + "$serde_json::private::Number": "2" + hasDiscount: true + scores: + descriptionCompleteness: + category: good + score: + "$serde_json::private::Number": "25" + imageQuality: + category: good + score: + "$serde_json::private::Number": "25" + inventoryAvailability: + score: + "$serde_json::private::Number": "8" + keywordOptimization: + score: + "$serde_json::private::Number": "15" + pricingCompetitiveness: + score: + "$serde_json::private::Number": "8" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + listing.description.hasBulletPoints: true + listing.description.hasSpecifications: true + listing.description.keywordDensity: + "$serde_json::private::Number": "3.2" + listing.description.wordCount: + "$serde_json::private::Number": "250" + listing.inventory.stockLevel: + "$serde_json::private::Number": "15" + listing.pricing.competitiveRank: + "$serde_json::private::Number": "2" + rule: + _id: desc-rule-2 + "listing.description.hasBulletPoints[hasBullets]": "true" + "listing.description.hasSpecifications[hasSpecs]": "" + "listing.description.keywordDensity[keywordDensity]": "> 1 and < 6" + "listing.description.wordCount[wordCount]": "> 200" + "listing.inventory.stockLevel[stockLevel]": "> 10" + "listing.pricing.competitiveRank[competitiveRank]": "< 5" + image-quality-node: + id: image-quality-node + input: + listing: + description: + hasBulletPoints: true + hasSpecifications: true + keywordDensity: + "$serde_json::private::Number": "3.2" + wordCount: + "$serde_json::private::Number": "250" + images: + count: + "$serde_json::private::Number": "4" + hasVariantImages: true + highResolution: true + inventory: + daysToShip: + "$serde_json::private::Number": "2" + stockLevel: + "$serde_json::private::Number": "15" + pricing: + competitiveRank: + "$serde_json::private::Number": "2" + hasDiscount: true + name: imageQuality + order: + "$serde_json::private::Number": "1" + output: + listing: + description: + hasBulletPoints: true + hasSpecifications: true + keywordDensity: + "$serde_json::private::Number": "3.2" + wordCount: + "$serde_json::private::Number": "250" + images: + count: + "$serde_json::private::Number": "4" + hasVariantImages: true + highResolution: true + inventory: + daysToShip: + "$serde_json::private::Number": "2" + stockLevel: + "$serde_json::private::Number": "15" + pricing: + competitiveRank: + "$serde_json::private::Number": "2" + hasDiscount: true + scores: + imageQuality: + category: good + score: + "$serde_json::private::Number": "25" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + listing.images.count: + "$serde_json::private::Number": "4" + listing.images.hasVariantImages: true + listing.images.highResolution: true + rule: + _id: img-rule-2 + "listing.images.count[imageCount]": ">= 3" + "listing.images.hasVariantImages[hasVariantImages]": "" + "listing.images.highResolution[highRes]": "true" + input-node: + id: input-node + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + listing: + description: + hasBulletPoints: true + hasSpecifications: true + keywordDensity: + "$serde_json::private::Number": "3.2" + wordCount: + "$serde_json::private::Number": "250" + images: + count: + "$serde_json::private::Number": "4" + hasVariantImages: true + highResolution: true + inventory: + daysToShip: + "$serde_json::private::Number": "2" + stockLevel: + "$serde_json::private::Number": "15" + pricing: + competitiveRank: + "$serde_json::private::Number": "2" + hasDiscount: true + performance: "[perf]" + traceData: ~ + overall-score-node: + id: overall-score-node + input: + listing: + description: + hasBulletPoints: true + hasSpecifications: true + keywordDensity: + "$serde_json::private::Number": "3.2" + wordCount: + "$serde_json::private::Number": "250" + images: + count: + "$serde_json::private::Number": "4" + hasVariantImages: true + highResolution: true + inventory: + daysToShip: + "$serde_json::private::Number": "2" + stockLevel: + "$serde_json::private::Number": "15" + pricing: + competitiveRank: + "$serde_json::private::Number": "2" + hasDiscount: true + scores: + descriptionCompleteness: + category: good + score: + "$serde_json::private::Number": "25" + imageQuality: + category: good + score: + "$serde_json::private::Number": "25" + inventoryAvailability: + score: + "$serde_json::private::Number": "8" + keywordOptimization: + score: + "$serde_json::private::Number": "15" + pricingCompetitiveness: + score: + "$serde_json::private::Number": "8" + name: overallScore + order: + "$serde_json::private::Number": "3" + output: + breakdown: + descriptionCompleteness: + category: good + score: + "$serde_json::private::Number": "25" + imageQuality: + category: good + score: + "$serde_json::private::Number": "25" + inventoryAvailability: + score: + "$serde_json::private::Number": "8" + keywordOptimization: + score: + "$serde_json::private::Number": "15" + pricingCompetitiveness: + score: + "$serde_json::private::Number": "8" + maximumPossibleScore: + "$serde_json::private::Number": "100" + overallScoreCategory: excellent + totalScore: + "$serde_json::private::Number": "81" + performance: "[perf]" + traceData: + breakdown: + result: "{\"inventoryAvailability\":{\"score\":8},\"descriptionCompleteness\":{\"category\":\"good\",\"score\":25},\"keywordOptimization\":{\"score\":15},\"pricingCompetitiveness\":{\"score\":8},\"imageQuality\":{\"score\":25,\"category\":\"good\"}}" + maximumPossibleScore: + result: "100" + overallScoreCategory: + result: "\"excellent\"" + totalScore: + result: "81" diff --git a/core/engine/tests/snapshots/engine__realtime-fraud-detection_0.snap b/core/engine/tests/snapshots/engine__realtime-fraud-detection_0.snap new file mode 100644 index 00000000..31be529e --- /dev/null +++ b/core/engine/tests/snapshots/engine__realtime-fraud-detection_0.snap @@ -0,0 +1,185 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + blockTransaction: false + finalRiskScore: + "$serde_json::private::Number": "75" + reason: Unusual location with amount significantly above average + requiresReview: true +trace: + fraudDetection: + id: fraudDetection + input: + transaction: + amount: + "$serde_json::private::Number": "1250" + date: 2023-03-18 + id: tx-28473 + location: Germany + merchantCategory: Electronics + recentCount: + "$serde_json::private::Number": "4" + time: "23:45" + userProfile: + averageTransactionAmount: + "$serde_json::private::Number": "350" + frequentCountries: + - Canada + - UK + homeCountry: USA + id: user-5932 + maxTransactionAmount: + "$serde_json::private::Number": "800" + usualMerchantCategories: + - Groceries + - Dining + - Retail + usualTransactionTimeRange: + - "08:00" + - "21:00" + name: detectSuspiciousActivity + order: + "$serde_json::private::Number": "1" + output: + fraud: + flag: high + reason: Unusual location with amount significantly above average + riskScore: + "$serde_json::private::Number": "75" + transaction: + amount: + "$serde_json::private::Number": "1250" + date: 2023-03-18 + id: tx-28473 + location: Germany + merchantCategory: Electronics + recentCount: + "$serde_json::private::Number": "4" + time: "23:45" + userProfile: + averageTransactionAmount: + "$serde_json::private::Number": "350" + frequentCountries: + - Canada + - UK + homeCountry: USA + id: user-5932 + maxTransactionAmount: + "$serde_json::private::Number": "800" + usualMerchantCategories: + - Groceries + - Dining + - Retail + usualTransactionTimeRange: + - "08:00" + - "21:00" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + transaction.amount: + "$serde_json::private::Number": "1250" + transaction.location: Germany + transaction.recentCount: + "$serde_json::private::Number": "4" + transaction.time: "23:45" + rule: + _id: rule1 + "transaction.amount[amountInput]": "> userProfile.averageTransactionAmount * 3" + "transaction.location[locationInput]": "!= userProfile.homeCountry and != userProfile.frequentCountries" + "transaction.recentCount[frequencyInput]": "" + "transaction.time[timeInput]": "" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + transaction: + amount: + "$serde_json::private::Number": "1250" + date: 2023-03-18 + id: tx-28473 + location: Germany + merchantCategory: Electronics + recentCount: + "$serde_json::private::Number": "4" + time: "23:45" + userProfile: + averageTransactionAmount: + "$serde_json::private::Number": "350" + frequentCountries: + - Canada + - UK + homeCountry: USA + id: user-5932 + maxTransactionAmount: + "$serde_json::private::Number": "800" + usualMerchantCategories: + - Groceries + - Dining + - Retail + usualTransactionTimeRange: + - "08:00" + - "21:00" + performance: "[perf]" + traceData: ~ + riskScoring: + id: riskScoring + input: + fraud: + flag: high + reason: Unusual location with amount significantly above average + riskScore: + "$serde_json::private::Number": "75" + transaction: + amount: + "$serde_json::private::Number": "1250" + date: 2023-03-18 + id: tx-28473 + location: Germany + merchantCategory: Electronics + recentCount: + "$serde_json::private::Number": "4" + time: "23:45" + userProfile: + averageTransactionAmount: + "$serde_json::private::Number": "350" + frequentCountries: + - Canada + - UK + homeCountry: USA + id: user-5932 + maxTransactionAmount: + "$serde_json::private::Number": "800" + usualMerchantCategories: + - Groceries + - Dining + - Retail + usualTransactionTimeRange: + - "08:00" + - "21:00" + name: calculateRiskScore + order: + "$serde_json::private::Number": "2" + output: + blockTransaction: false + finalRiskScore: + "$serde_json::private::Number": "75" + reason: Unusual location with amount significantly above average + requiresReview: true + performance: "[perf]" + traceData: + blockTransaction: + result: "false" + finalRiskScore: + result: "75" + reason: + result: "\"Unusual location with amount significantly above average\"" + requiresReview: + result: "true" diff --git a/core/engine/tests/snapshots/engine__regional-compliance-manager_0.snap b/core/engine/tests/snapshots/engine__regional-compliance-manager_0.snap new file mode 100644 index 00000000..c1fd84c9 --- /dev/null +++ b/core/engine/tests/snapshots/engine__regional-compliance-manager_0.snap @@ -0,0 +1,193 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + eligibility: + notes: Age verification required for premium services + premiumServices: true +trace: + additionalRestrictions: + id: additionalRestrictions + input: + compliance: + dataExportAllowed: false + dataRetentionMonths: + "$serde_json::private::Number": "24" + explicitConsentRequired: true + privacyFramework: GDPR + serviceRestrictions: + - roaming_cap + - third_party_data_sharing + complianceStatus: compliant + complianceSummary: "Region: EU, Framework: GDPR, Retention: 24 months" + customer: + age: + "$serde_json::private::Number": "32" + consentProvided: true + dateJoined: 2023-05-15 + id: CUST-83921 + region: EU + serviceLevel: standard + type: individual + dataRetentionDate: + "$serde_json::private::Number": "63963682995" + serviceRequest: + dataSharing: false + internationalRoaming: true + upgradeToPremium: true + name: serviceEligibility + order: + "$serde_json::private::Number": "3" + output: + eligibility: + notes: Age verification required for premium services + premiumServices: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + customer.region: EU + customer.type: individual + rule: + _id: eligible4 + "customer.region[region]": "'EU', 'UK'" + "customer.type[customerType]": "'individual'" + complianceOutput: + id: complianceOutput + input: + compliance: + dataExportAllowed: false + dataRetentionMonths: + "$serde_json::private::Number": "24" + explicitConsentRequired: true + privacyFramework: GDPR + serviceRestrictions: + - roaming_cap + - third_party_data_sharing + customer: + age: + "$serde_json::private::Number": "32" + consentProvided: true + dateJoined: 2023-05-15 + id: CUST-83921 + region: EU + serviceLevel: standard + type: individual + serviceRequest: + dataSharing: false + internationalRoaming: true + upgradeToPremium: true + name: complianceEvaluation + order: + "$serde_json::private::Number": "2" + output: + compliance: + dataExportAllowed: false + dataRetentionMonths: + "$serde_json::private::Number": "24" + explicitConsentRequired: true + privacyFramework: GDPR + serviceRestrictions: + - roaming_cap + - third_party_data_sharing + complianceStatus: compliant + complianceSummary: "Region: EU, Framework: GDPR, Retention: 24 months" + customer: + age: + "$serde_json::private::Number": "32" + consentProvided: true + dateJoined: 2023-05-15 + id: CUST-83921 + region: EU + serviceLevel: standard + type: individual + dataRetentionDate: + "$serde_json::private::Number": "63963682995" + serviceRequest: + dataSharing: false + internationalRoaming: true + upgradeToPremium: true + performance: "[perf]" + traceData: + complianceStatus: + result: "\"compliant\"" + complianceSummary: + result: "\"Region: EU, Framework: GDPR, Retention: 24 months\"" + dataRetentionDate: + result: "63963682995" + input: + id: input + input: ~ + name: customerData + order: + "$serde_json::private::Number": "0" + output: + customer: + age: + "$serde_json::private::Number": "32" + consentProvided: true + dateJoined: 2023-05-15 + id: CUST-83921 + region: EU + serviceLevel: standard + type: individual + serviceRequest: + dataSharing: false + internationalRoaming: true + upgradeToPremium: true + performance: "[perf]" + traceData: ~ + regionRules: + id: regionRules + input: + customer: + age: + "$serde_json::private::Number": "32" + consentProvided: true + dateJoined: 2023-05-15 + id: CUST-83921 + region: EU + serviceLevel: standard + type: individual + serviceRequest: + dataSharing: false + internationalRoaming: true + upgradeToPremium: true + name: regionalComplianceRules + order: + "$serde_json::private::Number": "1" + output: + compliance: + dataExportAllowed: false + dataRetentionMonths: + "$serde_json::private::Number": "24" + explicitConsentRequired: true + privacyFramework: GDPR + serviceRestrictions: + - roaming_cap + - third_party_data_sharing + customer: + age: + "$serde_json::private::Number": "32" + consentProvided: true + dateJoined: 2023-05-15 + id: CUST-83921 + region: EU + serviceLevel: standard + type: individual + serviceRequest: + dataSharing: false + internationalRoaming: true + upgradeToPremium: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + customer.region: EU + rule: + _id: rule1 + "customer.region[region]": "'EU'" diff --git a/core/engine/tests/snapshots/engine__returns-and-refund-policy_0.snap b/core/engine/tests/snapshots/engine__returns-and-refund-policy_0.snap new file mode 100644 index 00000000..1196125e --- /dev/null +++ b/core/engine/tests/snapshots/engine__returns-and-refund-policy_0.snap @@ -0,0 +1,334 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + buyerInfo: + id: USR-789 + returnHistory: + recentDisputes: + "$serde_json::private::Number": "0" + totalReturns: + "$serde_json::private::Number": "3" + daysSincePurchase: + "$serde_json::private::Number": "25" + itemCondition: new + orderInfo: + orderId: ORD-12345 + purchaseDate: 2023-10-15 + originalPrice: + "$serde_json::private::Number": "89.99" + processingTimeEstimate: + "$serde_json::private::Number": "5" + productDetails: + category: electronics + isWarrantyActive: true + refundAmount: + "$serde_json::private::Number": "89.99" + refundShipping: true + resolution: + note: Seller is responsible for product issues on new items. + refundApproved: true + responsibleParty: seller + returnReason: damaged + returnShippingCovered: true + returnStatus: + code: eligible + isEligible: true + message: The return is within policy timeframe and eligible for processing. + sellerPolicy: + freeReturnShipping: false + restockingFeePercent: + "$serde_json::private::Number": "15" + returnWindow: + "$serde_json::private::Number": "30" + returnsAllowed: true +trace: + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + buyerInfo: + id: USR-789 + returnHistory: + recentDisputes: + "$serde_json::private::Number": "0" + totalReturns: + "$serde_json::private::Number": "3" + daysSincePurchase: + "$serde_json::private::Number": "25" + itemCondition: new + orderInfo: + orderId: ORD-12345 + purchaseDate: 2023-10-15 + originalPrice: + "$serde_json::private::Number": "89.99" + productDetails: + category: electronics + isWarrantyActive: true + returnReason: damaged + sellerPolicy: + freeReturnShipping: false + restockingFeePercent: + "$serde_json::private::Number": "15" + returnWindow: + "$serde_json::private::Number": "30" + returnsAllowed: true + performance: "[perf]" + traceData: ~ + refundCalculation: + id: refundCalculation + input: + buyerInfo: + id: USR-789 + returnHistory: + recentDisputes: + "$serde_json::private::Number": "0" + totalReturns: + "$serde_json::private::Number": "3" + daysSincePurchase: + "$serde_json::private::Number": "25" + itemCondition: new + orderInfo: + orderId: ORD-12345 + purchaseDate: 2023-10-15 + originalPrice: + "$serde_json::private::Number": "89.99" + productDetails: + category: electronics + isWarrantyActive: true + resolution: + note: Seller is responsible for product issues on new items. + refundApproved: true + responsibleParty: seller + returnReason: damaged + returnStatus: + code: eligible + isEligible: true + message: The return is within policy timeframe and eligible for processing. + sellerPolicy: + freeReturnShipping: false + restockingFeePercent: + "$serde_json::private::Number": "15" + returnWindow: + "$serde_json::private::Number": "30" + returnsAllowed: true + name: refundCalculation + order: + "$serde_json::private::Number": "3" + output: + buyerInfo: + id: USR-789 + returnHistory: + recentDisputes: + "$serde_json::private::Number": "0" + totalReturns: + "$serde_json::private::Number": "3" + daysSincePurchase: + "$serde_json::private::Number": "25" + itemCondition: new + orderInfo: + orderId: ORD-12345 + purchaseDate: 2023-10-15 + originalPrice: + "$serde_json::private::Number": "89.99" + processingTimeEstimate: + "$serde_json::private::Number": "5" + productDetails: + category: electronics + isWarrantyActive: true + refundAmount: + "$serde_json::private::Number": "89.99" + refundShipping: true + resolution: + note: Seller is responsible for product issues on new items. + refundApproved: true + responsibleParty: seller + returnReason: damaged + returnShippingCovered: true + returnStatus: + code: eligible + isEligible: true + message: The return is within policy timeframe and eligible for processing. + sellerPolicy: + freeReturnShipping: false + restockingFeePercent: + "$serde_json::private::Number": "15" + returnWindow: + "$serde_json::private::Number": "30" + returnsAllowed: true + performance: "[perf]" + traceData: + processingTimeEstimate: + result: "5" + refundAmount: + result: "89.99" + refundShipping: + result: "true" + returnShippingCovered: + result: "true" + responsibilityDetermination: + id: responsibilityDetermination + input: + buyerInfo: + id: USR-789 + returnHistory: + recentDisputes: + "$serde_json::private::Number": "0" + totalReturns: + "$serde_json::private::Number": "3" + daysSincePurchase: + "$serde_json::private::Number": "25" + itemCondition: new + orderInfo: + orderId: ORD-12345 + purchaseDate: 2023-10-15 + originalPrice: + "$serde_json::private::Number": "89.99" + productDetails: + category: electronics + isWarrantyActive: true + returnReason: damaged + returnStatus: + code: eligible + isEligible: true + message: The return is within policy timeframe and eligible for processing. + sellerPolicy: + freeReturnShipping: false + restockingFeePercent: + "$serde_json::private::Number": "15" + returnWindow: + "$serde_json::private::Number": "30" + returnsAllowed: true + name: responsibilityDetermination + order: + "$serde_json::private::Number": "2" + output: + buyerInfo: + id: USR-789 + returnHistory: + recentDisputes: + "$serde_json::private::Number": "0" + totalReturns: + "$serde_json::private::Number": "3" + daysSincePurchase: + "$serde_json::private::Number": "25" + itemCondition: new + orderInfo: + orderId: ORD-12345 + purchaseDate: 2023-10-15 + originalPrice: + "$serde_json::private::Number": "89.99" + productDetails: + category: electronics + isWarrantyActive: true + resolution: + note: Seller is responsible for product issues on new items. + refundApproved: true + responsibleParty: seller + returnReason: damaged + returnStatus: + code: eligible + isEligible: true + message: The return is within policy timeframe and eligible for processing. + sellerPolicy: + freeReturnShipping: false + restockingFeePercent: + "$serde_json::private::Number": "15" + returnWindow: + "$serde_json::private::Number": "30" + returnsAllowed: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + itemCondition: new + returnReason: damaged + returnStatus.isEligible: true + rule: + _id: r2-1 + "itemCondition[i2-2]": "'new', 'like_new'" + "returnReason[i2-1]": "'damaged', 'defective'" + "returnStatus.isEligible[i2-3]": "true" + returnEligibility: + id: returnEligibility + input: + buyerInfo: + id: USR-789 + returnHistory: + recentDisputes: + "$serde_json::private::Number": "0" + totalReturns: + "$serde_json::private::Number": "3" + daysSincePurchase: + "$serde_json::private::Number": "25" + itemCondition: new + orderInfo: + orderId: ORD-12345 + purchaseDate: 2023-10-15 + originalPrice: + "$serde_json::private::Number": "89.99" + productDetails: + category: electronics + isWarrantyActive: true + returnReason: damaged + sellerPolicy: + freeReturnShipping: false + restockingFeePercent: + "$serde_json::private::Number": "15" + returnWindow: + "$serde_json::private::Number": "30" + returnsAllowed: true + name: returnEligibility + order: + "$serde_json::private::Number": "1" + output: + buyerInfo: + id: USR-789 + returnHistory: + recentDisputes: + "$serde_json::private::Number": "0" + totalReturns: + "$serde_json::private::Number": "3" + daysSincePurchase: + "$serde_json::private::Number": "25" + itemCondition: new + orderInfo: + orderId: ORD-12345 + purchaseDate: 2023-10-15 + originalPrice: + "$serde_json::private::Number": "89.99" + productDetails: + category: electronics + isWarrantyActive: true + returnReason: damaged + returnStatus: + code: eligible + isEligible: true + message: The return is within policy timeframe and eligible for processing. + sellerPolicy: + freeReturnShipping: false + restockingFeePercent: + "$serde_json::private::Number": "15" + returnWindow: + "$serde_json::private::Number": "30" + returnsAllowed: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + daysSincePurchase: + "$serde_json::private::Number": "25" + returnReason: damaged + sellerPolicy.returnsAllowed: true + rule: + _id: r1-1 + "daysSincePurchase[i1-1]": "< 30" + "returnReason[i1-3]": "'damaged', 'defective', 'wrong_item'" + "sellerPolicy.returnsAllowed[i1-2]": "true" diff --git a/core/engine/tests/snapshots/engine__returns-processing-system_0.snap b/core/engine/tests/snapshots/engine__returns-processing-system_0.snap new file mode 100644 index 00000000..36261568 --- /dev/null +++ b/core/engine/tests/snapshots/engine__returns-processing-system_0.snap @@ -0,0 +1,396 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + returnDetails: + customerCommunication: partial_approval + expectedProcessingDays: + "$serde_json::private::Number": "2" + priorityLevel: high + processingQueue: returns_dept + refundAmount: + "$serde_json::private::Number": "199.992" + restockingFee: + "$serde_json::private::Number": "10" + type: partial_refund +trace: + communicationTable: + id: communicationTable + input: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + returnDetails: + expectedProcessingDays: + "$serde_json::private::Number": "2" + priorityLevel: high + processingQueue: returns_dept + refundAmount: + "$serde_json::private::Number": "199.992" + restockingFee: + "$serde_json::private::Number": "10" + type: partial_refund + name: determineCommunication + order: + "$serde_json::private::Number": "5" + output: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + returnDetails: + customerCommunication: partial_approval + expectedProcessingDays: + "$serde_json::private::Number": "2" + priorityLevel: high + processingQueue: returns_dept + refundAmount: + "$serde_json::private::Number": "199.992" + restockingFee: + "$serde_json::private::Number": "10" + type: partial_refund + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + returnDetails.type: partial_refund + rule: + _id: comm2 + "returnDetails.type[returnType]": "'partial_refund', 'store_credit'" + customerStatus: + id: customerStatus + input: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + name: customerEligibility + order: + "$serde_json::private::Number": "1" + output: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + performance: "[perf]" + traceData: + isFrequentReturner: + result: "false" + isHighValueCustomer: + result: "true" + isHighValueItem: + result: "true" + isPurchaseWithinWarranty: + result: "true" + input1: + id: input1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + performance: "[perf]" + traceData: ~ + priorityLevelTable: + id: priorityLevelTable + input: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + returnDetails: + processingQueue: returns_dept + refundAmount: + "$serde_json::private::Number": "199.992" + restockingFee: + "$serde_json::private::Number": "10" + type: partial_refund + name: determinePriorityLevel + order: + "$serde_json::private::Number": "4" + output: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + returnDetails: + expectedProcessingDays: + "$serde_json::private::Number": "2" + priorityLevel: high + processingQueue: returns_dept + refundAmount: + "$serde_json::private::Number": "199.992" + restockingFee: + "$serde_json::private::Number": "10" + type: partial_refund + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + isHighValueCustomer: true + isHighValueItem: true + rule: + _id: priority1 + "isHighValueCustomer[highValueCustomer]": "true" + "isHighValueItem[highValueItem]": "" + processingQueueTable: + id: processingQueueTable + input: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + returnDetails: + refundAmount: + "$serde_json::private::Number": "199.992" + restockingFee: + "$serde_json::private::Number": "10" + type: partial_refund + name: determineProcessingQueue + order: + "$serde_json::private::Number": "3" + output: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + returnDetails: + processingQueue: returns_dept + refundAmount: + "$serde_json::private::Number": "199.992" + restockingFee: + "$serde_json::private::Number": "10" + type: partial_refund + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + returnDetails.type: partial_refund + rule: + _id: queue4 + "returnDetails.type[returnType]": "" + returnsClassification: + id: returnsClassification + input: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + name: determineReturnType + order: + "$serde_json::private::Number": "2" + output: + customer: + id: CUST-12345 + membershipTier: premium + returnsHistoryCount: + "$serde_json::private::Number": "3" + isFrequentReturner: false + isHighValueCustomer: true + isHighValueItem: true + isPurchaseWithinWarranty: true + product: + condition: damaged + daysFromPurchase: + "$serde_json::private::Number": "12" + price: + "$serde_json::private::Number": "249.99" + type: electronics + return: + hasReceipt: true + reason: "defective item - won't power on" + returnDetails: + refundAmount: + "$serde_json::private::Number": "199.992" + restockingFee: + "$serde_json::private::Number": "10" + type: partial_refund + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + product.condition: damaged + product.daysFromPurchase: + "$serde_json::private::Number": "12" + product.type: electronics + return.hasReceipt: true + return.reason: "defective item - won't power on" + rule: + _id: rule2 + "product.condition[productCondition]": "'damaged', 'opened'" + "product.daysFromPurchase[daysFromPurchase]": "<= 15" + "product.type[productType]": "'electronics', 'appliances'" + "return.hasReceipt[hasReceipt]": "true" + "return.reason[returnReason]": "" diff --git a/core/engine/tests/snapshots/engine__school-district-resource-allocation_0.snap b/core/engine/tests/snapshots/engine__school-district-resource-allocation_0.snap new file mode 100644 index 00000000..d3bc9fe3 --- /dev/null +++ b/core/engine/tests/snapshots/engine__school-district-resource-allocation_0.snap @@ -0,0 +1,316 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + adjusted_funding: + "$serde_json::private::Number": "4537500" + allocation: + base_funding: + "$serde_json::private::Number": "4125000" + school_size: medium + funding: + - allocation: + funding_descriptions: Special Education Support + program_funding: + "$serde_json::private::Number": "135000" + - allocation: + funding_descriptions: ESL Program Support + program_funding: + "$serde_json::private::Number": "200000" + - allocation: + funding_descriptions: STEM Program Support + program_funding: + "$serde_json::private::Number": "20000" + performance_multiplier: + "$serde_json::private::Number": "1.1" + performance_score: + "$serde_json::private::Number": "80" + school: + esl_students: + "$serde_json::private::Number": "80" + gifted_students: + "$serde_json::private::Number": "35" + id: sch_12345 + name: Washington High School + special_education_students: + "$serde_json::private::Number": "45" + special_programs: + - special_education + - esl + - stem + student_population: + "$serde_json::private::Number": "750" + test_scores: + math: + "$serde_json::private::Number": "82" + reading: + "$serde_json::private::Number": "78" + type: secondary +trace: + baseAllocationTable: + id: baseAllocationTable + input: + school: + esl_students: + "$serde_json::private::Number": "80" + gifted_students: + "$serde_json::private::Number": "35" + id: sch_12345 + name: Washington High School + special_education_students: + "$serde_json::private::Number": "45" + special_programs: + - special_education + - esl + - stem + student_population: + "$serde_json::private::Number": "750" + test_scores: + math: + "$serde_json::private::Number": "82" + reading: + "$serde_json::private::Number": "78" + type: secondary + name: baseAllocation + order: + "$serde_json::private::Number": "1" + output: + allocation: + base_funding: + "$serde_json::private::Number": "4125000" + school_size: medium + school: + esl_students: + "$serde_json::private::Number": "80" + gifted_students: + "$serde_json::private::Number": "35" + id: sch_12345 + name: Washington High School + special_education_students: + "$serde_json::private::Number": "45" + special_programs: + - special_education + - esl + - stem + student_population: + "$serde_json::private::Number": "750" + test_scores: + math: + "$serde_json::private::Number": "82" + reading: + "$serde_json::private::Number": "78" + type: secondary + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + school.student_population: + "$serde_json::private::Number": "750" + school.type: secondary + rule: + _id: r2 + "school.student_population[i1]": "> 500" + "school.type[i2]": "" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + school: + esl_students: + "$serde_json::private::Number": "80" + gifted_students: + "$serde_json::private::Number": "35" + id: sch_12345 + name: Washington High School + special_education_students: + "$serde_json::private::Number": "45" + special_programs: + - special_education + - esl + - stem + student_population: + "$serde_json::private::Number": "750" + test_scores: + math: + "$serde_json::private::Number": "82" + reading: + "$serde_json::private::Number": "78" + type: secondary + performance: "[perf]" + traceData: ~ + performanceAdjustment: + id: performanceAdjustment + input: + allocation: + base_funding: + "$serde_json::private::Number": "4125000" + school_size: medium + school: + esl_students: + "$serde_json::private::Number": "80" + gifted_students: + "$serde_json::private::Number": "35" + id: sch_12345 + name: Washington High School + special_education_students: + "$serde_json::private::Number": "45" + special_programs: + - special_education + - esl + - stem + student_population: + "$serde_json::private::Number": "750" + test_scores: + math: + "$serde_json::private::Number": "82" + reading: + "$serde_json::private::Number": "78" + type: secondary + name: performanceAdjustment + order: + "$serde_json::private::Number": "2" + output: + adjusted_funding: + "$serde_json::private::Number": "4537500" + allocation: + base_funding: + "$serde_json::private::Number": "4125000" + school_size: medium + performance_multiplier: + "$serde_json::private::Number": "1.1" + performance_score: + "$serde_json::private::Number": "80" + school: + esl_students: + "$serde_json::private::Number": "80" + gifted_students: + "$serde_json::private::Number": "35" + id: sch_12345 + name: Washington High School + special_education_students: + "$serde_json::private::Number": "45" + special_programs: + - special_education + - esl + - stem + student_population: + "$serde_json::private::Number": "750" + test_scores: + math: + "$serde_json::private::Number": "82" + reading: + "$serde_json::private::Number": "78" + type: secondary + performance: "[perf]" + traceData: + adjusted_funding: + result: "4537500" + performance_multiplier: + result: "1.1" + performance_score: + result: "80" + specialProgramsTable: + id: specialProgramsTable + input: + adjusted_funding: + "$serde_json::private::Number": "4537500" + allocation: + base_funding: + "$serde_json::private::Number": "4125000" + school_size: medium + performance_multiplier: + "$serde_json::private::Number": "1.1" + performance_score: + "$serde_json::private::Number": "80" + school: + esl_students: + "$serde_json::private::Number": "80" + gifted_students: + "$serde_json::private::Number": "35" + id: sch_12345 + name: Washington High School + special_education_students: + "$serde_json::private::Number": "45" + special_programs: + - special_education + - esl + - stem + student_population: + "$serde_json::private::Number": "750" + test_scores: + math: + "$serde_json::private::Number": "82" + reading: + "$serde_json::private::Number": "78" + type: secondary + name: specialProgramsAdjustment + order: + "$serde_json::private::Number": "3" + output: + adjusted_funding: + "$serde_json::private::Number": "4537500" + allocation: + base_funding: + "$serde_json::private::Number": "4125000" + school_size: medium + funding: + - allocation: + funding_descriptions: Special Education Support + program_funding: + "$serde_json::private::Number": "135000" + - allocation: + funding_descriptions: ESL Program Support + program_funding: + "$serde_json::private::Number": "200000" + - allocation: + funding_descriptions: STEM Program Support + program_funding: + "$serde_json::private::Number": "20000" + performance_multiplier: + "$serde_json::private::Number": "1.1" + performance_score: + "$serde_json::private::Number": "80" + school: + esl_students: + "$serde_json::private::Number": "80" + gifted_students: + "$serde_json::private::Number": "35" + id: sch_12345 + name: Washington High School + special_education_students: + "$serde_json::private::Number": "45" + special_programs: + - special_education + - esl + - stem + student_population: + "$serde_json::private::Number": "750" + test_scores: + math: + "$serde_json::private::Number": "82" + reading: + "$serde_json::private::Number": "78" + type: secondary + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: sp1 + - index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: sp2 + - index: + "$serde_json::private::Number": "3" + reference_map: {} + rule: + _id: sp4 diff --git a/core/engine/tests/snapshots/engine__seat-map-optimization_0.snap b/core/engine/tests/snapshots/engine__seat-map-optimization_0.snap new file mode 100644 index 00000000..3f56deac --- /dev/null +++ b/core/engine/tests/snapshots/engine__seat-map-optimization_0.snap @@ -0,0 +1,266 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + seatDisplay: + displayMessage: Select your seats + seatMapVersion: premium + totalAvailableSeats: + "$serde_json::private::Number": "72" +trace: + cabinFillCalculator: + id: cabinFillCalculator + input: + cabin: + id: CAB789 + name: main cabin + occupiedSeats: + "$serde_json::private::Number": "108" + premiumSeats: + "$serde_json::private::Number": "32" + restrictedSeats: + "$serde_json::private::Number": "10" + standardSeats: + "$serde_json::private::Number": "138" + totalSeats: + "$serde_json::private::Number": "180" + customer: + fareClass: economy_plus + groupSize: + "$serde_json::private::Number": "3" + hasSpecialNeeds: false + id: CUS123456 + previousFlights: + "$serde_json::private::Number": "24" + tier: gold + flight: + aircraft: Boeing 737-800 + arrivalTime: "2025-04-15T11:45:00Z" + departureTime: "2025-04-15T08:30:00Z" + flightNumber: FL722 + name: calculateCabinFill + order: + "$serde_json::private::Number": "1" + output: + adjacentSeatsNeeded: + "$serde_json::private::Number": "3" + cabin: + id: CAB789 + name: main cabin + occupiedSeats: + "$serde_json::private::Number": "108" + premiumSeats: + "$serde_json::private::Number": "32" + restrictedSeats: + "$serde_json::private::Number": "10" + standardSeats: + "$serde_json::private::Number": "138" + totalSeats: + "$serde_json::private::Number": "180" + cabinFillPercentage: + "$serde_json::private::Number": "60" + customer: + fareClass: economy_plus + groupSize: + "$serde_json::private::Number": "3" + hasSpecialNeeds: false + id: CUS123456 + previousFlights: + "$serde_json::private::Number": "24" + tier: gold + flight: + aircraft: Boeing 737-800 + arrivalTime: "2025-04-15T11:45:00Z" + departureTime: "2025-04-15T08:30:00Z" + flightNumber: FL722 + performance: "[perf]" + traceData: + adjacentSeatsNeeded: + result: "3" + cabinFillPercentage: + result: "60" + inputNode: + id: inputNode + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + cabin: + id: CAB789 + name: main cabin + occupiedSeats: + "$serde_json::private::Number": "108" + premiumSeats: + "$serde_json::private::Number": "32" + restrictedSeats: + "$serde_json::private::Number": "10" + standardSeats: + "$serde_json::private::Number": "138" + totalSeats: + "$serde_json::private::Number": "180" + customer: + fareClass: economy_plus + groupSize: + "$serde_json::private::Number": "3" + hasSpecialNeeds: false + id: CUS123456 + previousFlights: + "$serde_json::private::Number": "24" + tier: gold + flight: + aircraft: Boeing 737-800 + arrivalTime: "2025-04-15T11:45:00Z" + departureTime: "2025-04-15T08:30:00Z" + flightNumber: FL722 + performance: "[perf]" + traceData: ~ + seatAvailabilityAdjuster: + id: seatAvailabilityAdjuster + input: + adjacentSeatsNeeded: + "$serde_json::private::Number": "3" + cabin: + id: CAB789 + name: main cabin + occupiedSeats: + "$serde_json::private::Number": "108" + premiumSeats: + "$serde_json::private::Number": "32" + restrictedSeats: + "$serde_json::private::Number": "10" + standardSeats: + "$serde_json::private::Number": "138" + totalSeats: + "$serde_json::private::Number": "180" + cabinFillPercentage: + "$serde_json::private::Number": "60" + customer: + fareClass: economy_plus + groupSize: + "$serde_json::private::Number": "3" + hasSpecialNeeds: false + id: CUS123456 + previousFlights: + "$serde_json::private::Number": "24" + tier: gold + flight: + aircraft: Boeing 737-800 + arrivalTime: "2025-04-15T11:45:00Z" + departureTime: "2025-04-15T08:30:00Z" + flightNumber: FL722 + seatDisplay: + showPreferredSeats: true + showRestrictedSeats: false + showStandardSeats: true + unlockPremiumSeats: true + name: adjustSeatAvailability + order: + "$serde_json::private::Number": "3" + output: + seatDisplay: + displayMessage: Select your seats + seatMapVersion: premium + totalAvailableSeats: + "$serde_json::private::Number": "72" + performance: "[perf]" + traceData: + seatDisplay.displayMessage: + result: "\"Select your seats\"" + seatDisplay.seatMapVersion: + result: "\"premium\"" + seatDisplay.totalAvailableSeats: + result: "72" + seatMapRules: + id: seatMapRules + input: + adjacentSeatsNeeded: + "$serde_json::private::Number": "3" + cabin: + id: CAB789 + name: main cabin + occupiedSeats: + "$serde_json::private::Number": "108" + premiumSeats: + "$serde_json::private::Number": "32" + restrictedSeats: + "$serde_json::private::Number": "10" + standardSeats: + "$serde_json::private::Number": "138" + totalSeats: + "$serde_json::private::Number": "180" + cabinFillPercentage: + "$serde_json::private::Number": "60" + customer: + fareClass: economy_plus + groupSize: + "$serde_json::private::Number": "3" + hasSpecialNeeds: false + id: CUS123456 + previousFlights: + "$serde_json::private::Number": "24" + tier: gold + flight: + aircraft: Boeing 737-800 + arrivalTime: "2025-04-15T11:45:00Z" + departureTime: "2025-04-15T08:30:00Z" + flightNumber: FL722 + name: determineSeatAvailability + order: + "$serde_json::private::Number": "2" + output: + adjacentSeatsNeeded: + "$serde_json::private::Number": "3" + cabin: + id: CAB789 + name: main cabin + occupiedSeats: + "$serde_json::private::Number": "108" + premiumSeats: + "$serde_json::private::Number": "32" + restrictedSeats: + "$serde_json::private::Number": "10" + standardSeats: + "$serde_json::private::Number": "138" + totalSeats: + "$serde_json::private::Number": "180" + cabinFillPercentage: + "$serde_json::private::Number": "60" + customer: + fareClass: economy_plus + groupSize: + "$serde_json::private::Number": "3" + hasSpecialNeeds: false + id: CUS123456 + previousFlights: + "$serde_json::private::Number": "24" + tier: gold + flight: + aircraft: Boeing 737-800 + arrivalTime: "2025-04-15T11:45:00Z" + departureTime: "2025-04-15T08:30:00Z" + flightNumber: FL722 + seatDisplay: + showPreferredSeats: true + showRestrictedSeats: false + showStandardSeats: true + unlockPremiumSeats: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + adjacentSeatsNeeded: + "$serde_json::private::Number": "3" + cabinFillPercentage: + "$serde_json::private::Number": "60" + customer.fareClass: economy_plus + customer.tier: gold + rule: + _id: rule2 + "adjacentSeatsNeeded[adjacentSeats]": "" + "cabinFillPercentage[cabinFill]": "< 70" + "customer.fareClass[fareClass]": "'economy_plus', 'economy'" + "customer.tier[customerTier]": "'platinum', 'gold'" diff --git a/core/engine/tests/snapshots/engine__seller-approval-workflow_0.snap b/core/engine/tests/snapshots/engine__seller-approval-workflow_0.snap new file mode 100644 index 00000000..256849ff --- /dev/null +++ b/core/engine/tests/snapshots/engine__seller-approval-workflow_0.snap @@ -0,0 +1,373 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + approvalDate: + "$serde_json::private::Number": "1755682992" + score: + "$serde_json::private::Number": "85" + status: APPROVED +trace: + approvalResult: + id: approvalResult + input: + backgroundCheck: + creditScore: + "$serde_json::private::Number": "720" + criminalRecord: false + identityVerified: true + passed: true + businessCredentials: + businessName: TechGadgets LLC + businessType: Limited Liability Company + hasValidDocumentation: true + taxId: 12-3456789 + yearsInBusiness: + "$serde_json::private::Number": "2.5" + categoryExpertise: + certifications: + - Consumer Electronics Specialist + primaryCategory: Electronics + rating: + "$serde_json::private::Number": "4" + yearsOfExperience: + "$serde_json::private::Number": "3" + evaluation: + businessStatus: established + credentialNotes: Established business with moderate history + credentialScore: + "$serde_json::private::Number": "25" + finalScore: + "$serde_json::private::Number": "85" + isApproved: true + notes: Strong seller profile with good expertise and inventory + inventoryQuality: + brandAuthenticity: true + productCompliance: true + productImageQuality: high + rating: + "$serde_json::private::Number": "4.2" + sampleProducts: + "$serde_json::private::Number": "15" + name: generateApprovalResult + order: + "$serde_json::private::Number": "4" + output: + approvalDate: + "$serde_json::private::Number": "1755682992" + score: + "$serde_json::private::Number": "85" + status: APPROVED + performance: "[perf]" + traceData: + approvalDate: + result: "1755682992" + score: + result: "85" + status: + result: "\"APPROVED\"" + approvalSwitch: + id: approvalSwitch + input: + backgroundCheck: + creditScore: + "$serde_json::private::Number": "720" + criminalRecord: false + identityVerified: true + passed: true + businessCredentials: + businessName: TechGadgets LLC + businessType: Limited Liability Company + hasValidDocumentation: true + taxId: 12-3456789 + yearsInBusiness: + "$serde_json::private::Number": "2.5" + categoryExpertise: + certifications: + - Consumer Electronics Specialist + primaryCategory: Electronics + rating: + "$serde_json::private::Number": "4" + yearsOfExperience: + "$serde_json::private::Number": "3" + evaluation: + businessStatus: established + credentialNotes: Established business with moderate history + credentialScore: + "$serde_json::private::Number": "25" + finalScore: + "$serde_json::private::Number": "85" + isApproved: true + notes: Strong seller profile with good expertise and inventory + inventoryQuality: + brandAuthenticity: true + productCompliance: true + productImageQuality: high + rating: + "$serde_json::private::Number": "4.2" + sampleProducts: + "$serde_json::private::Number": "15" + name: routeApplication + order: + "$serde_json::private::Number": "3" + output: + backgroundCheck: + creditScore: + "$serde_json::private::Number": "720" + criminalRecord: false + identityVerified: true + passed: true + businessCredentials: + businessName: TechGadgets LLC + businessType: Limited Liability Company + hasValidDocumentation: true + taxId: 12-3456789 + yearsInBusiness: + "$serde_json::private::Number": "2.5" + categoryExpertise: + certifications: + - Consumer Electronics Specialist + primaryCategory: Electronics + rating: + "$serde_json::private::Number": "4" + yearsOfExperience: + "$serde_json::private::Number": "3" + evaluation: + businessStatus: established + credentialNotes: Established business with moderate history + credentialScore: + "$serde_json::private::Number": "25" + finalScore: + "$serde_json::private::Number": "85" + isApproved: true + notes: Strong seller profile with good expertise and inventory + inventoryQuality: + brandAuthenticity: true + productCompliance: true + productImageQuality: high + rating: + "$serde_json::private::Number": "4.2" + sampleProducts: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: + statements: + - id: approved + businessCredentialsTable: + id: businessCredentialsTable + input: + backgroundCheck: + creditScore: + "$serde_json::private::Number": "720" + criminalRecord: false + identityVerified: true + passed: true + businessCredentials: + businessName: TechGadgets LLC + businessType: Limited Liability Company + hasValidDocumentation: true + taxId: 12-3456789 + yearsInBusiness: + "$serde_json::private::Number": "2.5" + categoryExpertise: + certifications: + - Consumer Electronics Specialist + primaryCategory: Electronics + rating: + "$serde_json::private::Number": "4" + yearsOfExperience: + "$serde_json::private::Number": "3" + inventoryQuality: + brandAuthenticity: true + productCompliance: true + productImageQuality: high + rating: + "$serde_json::private::Number": "4.2" + sampleProducts: + "$serde_json::private::Number": "15" + name: evaluateBusinessCredentials + order: + "$serde_json::private::Number": "1" + output: + backgroundCheck: + creditScore: + "$serde_json::private::Number": "720" + criminalRecord: false + identityVerified: true + passed: true + businessCredentials: + businessName: TechGadgets LLC + businessType: Limited Liability Company + hasValidDocumentation: true + taxId: 12-3456789 + yearsInBusiness: + "$serde_json::private::Number": "2.5" + categoryExpertise: + certifications: + - Consumer Electronics Specialist + primaryCategory: Electronics + rating: + "$serde_json::private::Number": "4" + yearsOfExperience: + "$serde_json::private::Number": "3" + evaluation: + businessStatus: established + credentialNotes: Established business with moderate history + credentialScore: + "$serde_json::private::Number": "25" + inventoryQuality: + brandAuthenticity: true + productCompliance: true + productImageQuality: high + rating: + "$serde_json::private::Number": "4.2" + sampleProducts: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + businessCredentials.hasValidDocumentation: true + businessCredentials.yearsInBusiness: + "$serde_json::private::Number": "2.5" + rule: + _id: r3 + "businessCredentials.hasValidDocumentation[i1-1]": "true" + "businessCredentials.yearsInBusiness[i1-2]": "[1..3)" + input: + id: input + input: ~ + name: sellerApplicationRequest + order: + "$serde_json::private::Number": "0" + output: + backgroundCheck: + creditScore: + "$serde_json::private::Number": "720" + criminalRecord: false + identityVerified: true + passed: true + businessCredentials: + businessName: TechGadgets LLC + businessType: Limited Liability Company + hasValidDocumentation: true + taxId: 12-3456789 + yearsInBusiness: + "$serde_json::private::Number": "2.5" + categoryExpertise: + certifications: + - Consumer Electronics Specialist + primaryCategory: Electronics + rating: + "$serde_json::private::Number": "4" + yearsOfExperience: + "$serde_json::private::Number": "3" + inventoryQuality: + brandAuthenticity: true + productCompliance: true + productImageQuality: high + rating: + "$serde_json::private::Number": "4.2" + sampleProducts: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: ~ + sellerEvaluationTable: + id: sellerEvaluationTable + input: + backgroundCheck: + creditScore: + "$serde_json::private::Number": "720" + criminalRecord: false + identityVerified: true + passed: true + businessCredentials: + businessName: TechGadgets LLC + businessType: Limited Liability Company + hasValidDocumentation: true + taxId: 12-3456789 + yearsInBusiness: + "$serde_json::private::Number": "2.5" + categoryExpertise: + certifications: + - Consumer Electronics Specialist + primaryCategory: Electronics + rating: + "$serde_json::private::Number": "4" + yearsOfExperience: + "$serde_json::private::Number": "3" + evaluation: + businessStatus: established + credentialNotes: Established business with moderate history + credentialScore: + "$serde_json::private::Number": "25" + inventoryQuality: + brandAuthenticity: true + productCompliance: true + productImageQuality: high + rating: + "$serde_json::private::Number": "4.2" + sampleProducts: + "$serde_json::private::Number": "15" + name: evaluateSellerQualifications + order: + "$serde_json::private::Number": "2" + output: + backgroundCheck: + creditScore: + "$serde_json::private::Number": "720" + criminalRecord: false + identityVerified: true + passed: true + businessCredentials: + businessName: TechGadgets LLC + businessType: Limited Liability Company + hasValidDocumentation: true + taxId: 12-3456789 + yearsInBusiness: + "$serde_json::private::Number": "2.5" + categoryExpertise: + certifications: + - Consumer Electronics Specialist + primaryCategory: Electronics + rating: + "$serde_json::private::Number": "4" + yearsOfExperience: + "$serde_json::private::Number": "3" + evaluation: + businessStatus: established + credentialNotes: Established business with moderate history + credentialScore: + "$serde_json::private::Number": "25" + finalScore: + "$serde_json::private::Number": "85" + isApproved: true + notes: Strong seller profile with good expertise and inventory + inventoryQuality: + brandAuthenticity: true + productCompliance: true + productImageQuality: high + rating: + "$serde_json::private::Number": "4.2" + sampleProducts: + "$serde_json::private::Number": "15" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + backgroundCheck.passed: true + categoryExpertise.rating: + "$serde_json::private::Number": "4" + evaluation.businessStatus: established + inventoryQuality.rating: + "$serde_json::private::Number": "4.2" + rule: + _id: r5 + "backgroundCheck.passed[i2-4]": "true" + "categoryExpertise.rating[i2-2]": ">= 3" + "evaluation.businessStatus[i2-1]": "" + "inventoryQuality.rating[i2-3]": ">= 3" diff --git a/core/engine/tests/snapshots/engine__seller-fee-calculator_0.snap b/core/engine/tests/snapshots/engine__seller-fee-calculator_0.snap new file mode 100644 index 00000000..9f0a24d7 --- /dev/null +++ b/core/engine/tests/snapshots/engine__seller-fee-calculator_0.snap @@ -0,0 +1,157 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + effectiveFeeRate: + "$serde_json::private::Number": "0.07" + totalMonthlyFee: + "$serde_json::private::Number": "5139.99" + transactionFee: + "$serde_json::private::Number": "5040" +trace: + additionalFees: + id: additionalFees + input: + fees: + baseFeeRate: + "$serde_json::private::Number": "0.1" + subscriptionFee: + "$serde_json::private::Number": "99.99" + subscriptionTier: premium + sellerData: + category: premium + inSpecialProgram: true + monthlySalesVolume: + "$serde_json::private::Number": "72000" + performanceRating: + "$serde_json::private::Number": "4.9" + name: calculateAdditionalFees + order: + "$serde_json::private::Number": "2" + output: + fees: + additionalServiceCharge: + "$serde_json::private::Number": "0" + baseFeeRate: + "$serde_json::private::Number": "0.1" + hasPromotionalBenefits: true + rateAdjustment: + "$serde_json::private::Number": "-0.03" + subscriptionFee: + "$serde_json::private::Number": "99.99" + subscriptionTier: premium + sellerData: + category: premium + inSpecialProgram: true + monthlySalesVolume: + "$serde_json::private::Number": "72000" + performanceRating: + "$serde_json::private::Number": "4.9" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + sellerData.inSpecialProgram: true + sellerData.performanceRating: + "$serde_json::private::Number": "4.9" + rule: + _id: addRule1 + "sellerData.inSpecialProgram[i2]": "true" + "sellerData.performanceRating[i1]": "> 4.8" + calculateTotal: + id: calculateTotal + input: + fees: + additionalServiceCharge: + "$serde_json::private::Number": "0" + baseFeeRate: + "$serde_json::private::Number": "0.1" + hasPromotionalBenefits: true + rateAdjustment: + "$serde_json::private::Number": "-0.03" + subscriptionFee: + "$serde_json::private::Number": "99.99" + subscriptionTier: premium + sellerData: + category: premium + inSpecialProgram: true + monthlySalesVolume: + "$serde_json::private::Number": "72000" + performanceRating: + "$serde_json::private::Number": "4.9" + name: calculateTotalFees + order: + "$serde_json::private::Number": "3" + output: + effectiveFeeRate: + "$serde_json::private::Number": "0.07" + totalMonthlyFee: + "$serde_json::private::Number": "5139.99" + transactionFee: + "$serde_json::private::Number": "5040" + performance: "[perf]" + traceData: + effectiveFeeRate: + result: "0.07" + totalMonthlyFee: + result: "5139.99" + transactionFee: + result: "5040" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + sellerData: + category: premium + inSpecialProgram: true + monthlySalesVolume: + "$serde_json::private::Number": "72000" + performanceRating: + "$serde_json::private::Number": "4.9" + performance: "[perf]" + traceData: ~ + sellerCategory: + id: sellerCategory + input: + sellerData: + category: premium + inSpecialProgram: true + monthlySalesVolume: + "$serde_json::private::Number": "72000" + performanceRating: + "$serde_json::private::Number": "4.9" + name: determineCategoryFees + order: + "$serde_json::private::Number": "1" + output: + fees: + baseFeeRate: + "$serde_json::private::Number": "0.1" + subscriptionFee: + "$serde_json::private::Number": "99.99" + subscriptionTier: premium + sellerData: + category: premium + inSpecialProgram: true + monthlySalesVolume: + "$serde_json::private::Number": "72000" + performanceRating: + "$serde_json::private::Number": "4.9" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + sellerData.category: premium + sellerData.monthlySalesVolume: + "$serde_json::private::Number": "72000" + rule: + _id: rule2 + "sellerData.category[i1]": "'premium'" + "sellerData.monthlySalesVolume[i2]": "> 50000" diff --git a/core/engine/tests/snapshots/engine__service-level-agreement-enforcement_0.snap b/core/engine/tests/snapshots/engine__service-level-agreement-enforcement_0.snap new file mode 100644 index 00000000..d7503aee --- /dev/null +++ b/core/engine/tests/snapshots/engine__service-level-agreement-enforcement_0.snap @@ -0,0 +1,599 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + breachDescription: Excessive downtime for premium customer + compensationAmount: + "$serde_json::private::Number": "225" + compensationType: service_credit + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + escalationLevel: senior_management + escalationTimeframe: immediate + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + requiresEscalation: true + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + severityLevel: critical + severityScore: + "$serde_json::private::Number": "3" + slaBreached: true +trace: + assessSLABreach: + id: assessSLABreach + input: + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + name: assessSLABreach + order: + "$serde_json::private::Number": "3" + output: + breachDescription: Excessive downtime for premium customer + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + slaBreached: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + customerTier: premium + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + rule: + _id: rule1 + "customerTier[serviceLevel]": "'premium'" + "parameterType[paramType]": "'downtime'" + "parameterValue[paramValue]": "> 10" + determineEscalation: + id: determineEscalation + input: + breachDescription: Excessive downtime for premium customer + compensationAmount: + "$serde_json::private::Number": "225" + compensationType: service_credit + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + severityLevel: critical + severityScore: + "$serde_json::private::Number": "3" + slaBreached: true + name: determineEscalation + order: + "$serde_json::private::Number": "6" + output: + breachDescription: Excessive downtime for premium customer + compensationAmount: + "$serde_json::private::Number": "225" + compensationType: service_credit + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + escalationLevel: senior_management + escalationTimeframe: immediate + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + requiresEscalation: true + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + severityLevel: critical + severityScore: + "$serde_json::private::Number": "3" + slaBreached: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + severityLevel: critical + rule: + _description: "" + _id: escalation1 + "severityLevel[i1]": "'critical'" + determineParameterType: + id: determineParameterType + input: + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + name: determineParameterType + order: + "$serde_json::private::Number": "2" + output: + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: param1 + determineSeverity: + id: determineSeverity + input: + breachDescription: Excessive downtime for premium customer + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + slaBreached: true + name: determineSeverity + order: + "$serde_json::private::Number": "4" + output: + breachDescription: Excessive downtime for premium customer + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + severityLevel: critical + severityScore: + "$serde_json::private::Number": "3" + slaBreached: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + customerTier: premium + parameterType: downtime + slaBreached: true + rule: + _description: "" + _id: severity1 + "customerTier[d3d1e8b0-5f9f-4867-a326-8cfdbccdbb94]": "'premium'" + "parameterType[3b99eee0-25eb-49b6-8cf0-6daa7fcbfdc3]": "'downtime'" + "slaBreached[10022132-3b17-452f-9e87-cc67dcbc1682]": "true" + ed8355c4-aea1-4526-82b3-56d7d98efa92: + id: ed8355c4-aea1-4526-82b3-56d7d98efa92 + input: + breachDescription: Excessive downtime for premium customer + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + severityLevel: critical + severityScore: + "$serde_json::private::Number": "3" + slaBreached: true + name: calculateCompensation + order: + "$serde_json::private::Number": "5" + output: + breachDescription: Excessive downtime for premium customer + compensationAmount: + "$serde_json::private::Number": "225" + compensationType: service_credit + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + parameterType: downtime + parameterValue: + "$serde_json::private::Number": "45" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + severityLevel: critical + severityScore: + "$serde_json::private::Number": "3" + slaBreached: true + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + customerTier: premium + slaBreached: true + rule: + _description: "" + _id: 32a4f6a9-6631-4a5b-9fad-75c5f22bb591 + "customerTier[f74a521d-8f22-47ba-b800-1c7a8e69d606]": "'premium'" + "slaBreached[bd7b183b-2e9f-4fec-bc0f-e915864bd5eb]": "true" + input1: + id: input1 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + performance: "[perf]" + traceData: ~ + validateSLA: + id: validateSLA + input: + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + name: validateServiceParameters + order: + "$serde_json::private::Number": "1" + output: + customer: + contactEmail: support@acmecorp.com + contractId: contract_456 + id: cust_789 + name: Acme Corporation + serviceTier: premium + customerTier: premium + downtimeDuration: + "$serde_json::private::Number": "45" + incident: + id: inc_123456 + reportedBy: automated_monitoring + reportedTime: "2025-03-19T15:45:00Z" + isDowntime: true + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + service: + downtimeDuration: + "$serde_json::private::Number": "45" + id: internet_service_123 + name: Business Fiber Internet + packetLoss: + "$serde_json::private::Number": "0.8" + responseTime: + "$serde_json::private::Number": "320" + startTime: "2025-03-19T15:30:00Z" + status: down + performance: "[perf]" + traceData: + customerTier: + result: "\"premium\"" + downtimeDuration: + result: "45" + isDowntime: + result: "true" + packetLoss: + result: "0.8" + responseTime: + result: "320" diff --git a/core/engine/tests/snapshots/engine__set-fee_0.snap b/core/engine/tests/snapshots/engine__set-fee_0.snap new file mode 100644 index 00000000..df9e6d22 --- /dev/null +++ b/core/engine/tests/snapshots/engine__set-fee_0.snap @@ -0,0 +1,127 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + amount: + "$serde_json::private::Number": "100" + cat_1: + "$serde_json::private::Number": "3" + cat_2: + "$serde_json::private::Number": "4" + country: US + currency: EUR + fee: + "$serde_json::private::Number": "0.6" + percent: + "$serde_json::private::Number": "4" +trace: + 09ecc83e-f89b-491b-9bfb-39311323ab94: + id: 09ecc83e-f89b-491b-9bfb-39311323ab94 + input: + amount: + "$serde_json::private::Number": "100" + country: US + currency: EUR + name: vars + order: + "$serde_json::private::Number": "3" + output: + amount: + "$serde_json::private::Number": "100" + cat_1: + "$serde_json::private::Number": "3" + cat_2: + "$serde_json::private::Number": "4" + country: US + currency: EUR + performance: "[perf]" + traceData: + cat_1: + result: "3" + cat_2: + result: "4" + 3a801d19-b611-4163-bfdd-f247a689a275: + id: 3a801d19-b611-4163-bfdd-f247a689a275 + input: + amount: + "$serde_json::private::Number": "100" + country: US + currency: EUR + name: pricing + order: + "$serde_json::private::Number": "1" + output: + amount: + "$serde_json::private::Number": "100" + country: US + currency: EUR + performance: "[perf]" + traceData: ~ + 5e3c541a-7cf3-4765-b4c0-e20d07510379: + id: 5e3c541a-7cf3-4765-b4c0-e20d07510379 + input: + amount: + "$serde_json::private::Number": "100" + cat_1: + "$serde_json::private::Number": "3" + cat_2: + "$serde_json::private::Number": "4" + country: US + currency: EUR + name: set percent + order: + "$serde_json::private::Number": "4" + output: + amount: + "$serde_json::private::Number": "100" + cat_1: + "$serde_json::private::Number": "3" + cat_2: + "$serde_json::private::Number": "4" + country: US + currency: EUR + fee: + "$serde_json::private::Number": "0.6" + percent: + "$serde_json::private::Number": "4" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: {} + rule: + _id: dbe9b32c-73be-4d16-b67e-fcc087a38a86 + bf832d94-d01d-4842-a60b-3db28375bccb: + id: bf832d94-d01d-4842-a60b-3db28375bccb + input: + amount: + "$serde_json::private::Number": "100" + country: US + currency: EUR + name: fee set? + order: + "$serde_json::private::Number": "2" + output: + amount: + "$serde_json::private::Number": "100" + country: US + currency: EUR + performance: "[perf]" + traceData: + statements: + - id: 94664df3-8233-4019-8381-affec373bffe + e0f3612a-6019-4647-a682-4f3019b67fce: + id: e0f3612a-6019-4647-a682-4f3019b67fce + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + amount: + "$serde_json::private::Number": "100" + country: US + currency: EUR + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__set-fee_1.snap b/core/engine/tests/snapshots/engine__set-fee_1.snap new file mode 100644 index 00000000..4839cd70 --- /dev/null +++ b/core/engine/tests/snapshots/engine__set-fee_1.snap @@ -0,0 +1,98 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + amount: + "$serde_json::private::Number": "110" + country: US + currency: USD + fee: + "$serde_json::private::Number": "0.5" + percent: + "$serde_json::private::Number": "1" +trace: + 1a8c6564-c566-44ff-b07a-bce27d7f5a02: + id: 1a8c6564-c566-44ff-b07a-bce27d7f5a02 + input: + amount: + "$serde_json::private::Number": "110" + country: US + currency: USD + fee: + "$serde_json::private::Number": "0.5" + percent: + "$serde_json::private::Number": "1" + name: response + order: + "$serde_json::private::Number": "3" + output: ~ + performance: "[perf]" + traceData: ~ + 3a801d19-b611-4163-bfdd-f247a689a275: + id: 3a801d19-b611-4163-bfdd-f247a689a275 + input: + amount: + "$serde_json::private::Number": "110" + country: US + currency: USD + name: pricing + order: + "$serde_json::private::Number": "1" + output: + amount: + "$serde_json::private::Number": "110" + country: US + currency: USD + fee: + "$serde_json::private::Number": "0.5" + percent: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: 6d08b48b-fe57-4efe-8d97-1bce5fcc75e8 + bf832d94-d01d-4842-a60b-3db28375bccb: + id: bf832d94-d01d-4842-a60b-3db28375bccb + input: + amount: + "$serde_json::private::Number": "110" + country: US + currency: USD + fee: + "$serde_json::private::Number": "0.5" + percent: + "$serde_json::private::Number": "1" + name: fee set? + order: + "$serde_json::private::Number": "2" + output: + amount: + "$serde_json::private::Number": "110" + country: US + currency: USD + fee: + "$serde_json::private::Number": "0.5" + percent: + "$serde_json::private::Number": "1" + performance: "[perf]" + traceData: + statements: + - id: 718244e6-9471-4d20-af18-fce456d36f7e + e0f3612a-6019-4647-a682-4f3019b67fce: + id: e0f3612a-6019-4647-a682-4f3019b67fce + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + amount: + "$serde_json::private::Number": "110" + country: US + currency: USD + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__set-fee_2.snap b/core/engine/tests/snapshots/engine__set-fee_2.snap new file mode 100644 index 00000000..8e78c5c8 --- /dev/null +++ b/core/engine/tests/snapshots/engine__set-fee_2.snap @@ -0,0 +1,127 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + amount: + "$serde_json::private::Number": "110" + cat_1: + "$serde_json::private::Number": "3" + cat_2: + "$serde_json::private::Number": "4" + country: CA + currency: AUD + fee: + "$serde_json::private::Number": "0.7" + percent: + "$serde_json::private::Number": "3" +trace: + 09ecc83e-f89b-491b-9bfb-39311323ab94: + id: 09ecc83e-f89b-491b-9bfb-39311323ab94 + input: + amount: + "$serde_json::private::Number": "110" + country: CA + currency: AUD + name: vars + order: + "$serde_json::private::Number": "3" + output: + amount: + "$serde_json::private::Number": "110" + cat_1: + "$serde_json::private::Number": "3" + cat_2: + "$serde_json::private::Number": "4" + country: CA + currency: AUD + performance: "[perf]" + traceData: + cat_1: + result: "3" + cat_2: + result: "4" + 3a801d19-b611-4163-bfdd-f247a689a275: + id: 3a801d19-b611-4163-bfdd-f247a689a275 + input: + amount: + "$serde_json::private::Number": "110" + country: CA + currency: AUD + name: pricing + order: + "$serde_json::private::Number": "1" + output: + amount: + "$serde_json::private::Number": "110" + country: CA + currency: AUD + performance: "[perf]" + traceData: ~ + 5e3c541a-7cf3-4765-b4c0-e20d07510379: + id: 5e3c541a-7cf3-4765-b4c0-e20d07510379 + input: + amount: + "$serde_json::private::Number": "110" + cat_1: + "$serde_json::private::Number": "3" + cat_2: + "$serde_json::private::Number": "4" + country: CA + currency: AUD + name: set percent + order: + "$serde_json::private::Number": "4" + output: + amount: + "$serde_json::private::Number": "110" + cat_1: + "$serde_json::private::Number": "3" + cat_2: + "$serde_json::private::Number": "4" + country: CA + currency: AUD + fee: + "$serde_json::private::Number": "0.7" + percent: + "$serde_json::private::Number": "3" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: {} + rule: + _id: 34388171-596a-4159-bc8b-493a9858e992 + bf832d94-d01d-4842-a60b-3db28375bccb: + id: bf832d94-d01d-4842-a60b-3db28375bccb + input: + amount: + "$serde_json::private::Number": "110" + country: CA + currency: AUD + name: fee set? + order: + "$serde_json::private::Number": "2" + output: + amount: + "$serde_json::private::Number": "110" + country: CA + currency: AUD + performance: "[perf]" + traceData: + statements: + - id: 94664df3-8233-4019-8381-affec373bffe + e0f3612a-6019-4647-a682-4f3019b67fce: + id: e0f3612a-6019-4647-a682-4f3019b67fce + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + amount: + "$serde_json::private::Number": "110" + country: CA + currency: AUD + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__shipping-carrier-selector_0.snap b/core/engine/tests/snapshots/engine__shipping-carrier-selector_0.snap new file mode 100644 index 00000000..92e10b61 --- /dev/null +++ b/core/engine/tests/snapshots/engine__shipping-carrier-selector_0.snap @@ -0,0 +1,328 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + baseCosts: + EcoShip: + "$serde_json::private::Number": "21.75" + FastTrack: + "$serde_json::private::Number": "40.5" + GlobalExpress: + "$serde_json::private::Number": "87.5" + GlobalStandard: + "$serde_json::private::Number": "60" + HeavyHauler: + "$serde_json::private::Number": "65" + QuickShip: + "$serde_json::private::Number": "39.75" + RegularPost: + "$serde_json::private::Number": "25" + SpeedyExpress: + "$serde_json::private::Number": "56.25" + StandardCourier: + "$serde_json::private::Number": "28.25" + WorldWide: + "$serde_json::private::Number": "77.5" + carrierCosts: + - carrier: FastTrack + cost: + "$serde_json::private::Number": "40.5" + - carrier: QuickShip + cost: + "$serde_json::private::Number": "39.75" + chargableWeight: + "$serde_json::private::Number": "12.5" + deliveryTimeline: express + destination: domestic + eligibleCarriers: + - FastTrack + - QuickShip + height: + "$serde_json::private::Number": "25" + isOversized: false + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + serviceLevel: express + validation: + isValid: true + volumetricWeight: + "$serde_json::private::Number": "7.875" + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" +trace: + 1842fd5e-dc7e-480e-b501-07f93500a14c: + id: 1842fd5e-dc7e-480e-b501-07f93500a14c + input: + deliveryTimeline: express + destination: domestic + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + validation: + isValid: true + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + name: switch1 + order: + "$serde_json::private::Number": "2" + output: + deliveryTimeline: express + destination: domestic + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + validation: + isValid: true + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + statements: + - id: de01933e-42a2-4995-8f84-9b9ab0a3d1ec + carrierEligibility: + id: carrierEligibility + input: + deliveryTimeline: express + destination: domestic + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + serviceLevel: express + validation: + isValid: true + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + name: determineEligibleCarriers + order: + "$serde_json::private::Number": "4" + output: + deliveryTimeline: express + destination: domestic + eligibleCarriers: + - carriers: + - FastTrack + - QuickShip + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + serviceLevel: express + validation: + isValid: true + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "2" + reference_map: {} + rule: + _id: rule3 + costCalculation: + id: costCalculation + input: + deliveryTimeline: express + destination: domestic + eligibleCarriers: + - carriers: + - FastTrack + - QuickShip + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + serviceLevel: express + validation: + isValid: true + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + name: calculateCosts + order: + "$serde_json::private::Number": "5" + output: + baseCosts: + EcoShip: + "$serde_json::private::Number": "21.75" + FastTrack: + "$serde_json::private::Number": "40.5" + GlobalExpress: + "$serde_json::private::Number": "87.5" + GlobalStandard: + "$serde_json::private::Number": "60" + HeavyHauler: + "$serde_json::private::Number": "65" + QuickShip: + "$serde_json::private::Number": "39.75" + RegularPost: + "$serde_json::private::Number": "25" + SpeedyExpress: + "$serde_json::private::Number": "56.25" + StandardCourier: + "$serde_json::private::Number": "28.25" + WorldWide: + "$serde_json::private::Number": "77.5" + carrierCosts: + - carrier: FastTrack + cost: + "$serde_json::private::Number": "40.5" + - carrier: QuickShip + cost: + "$serde_json::private::Number": "39.75" + chargableWeight: + "$serde_json::private::Number": "12.5" + deliveryTimeline: express + destination: domestic + eligibleCarriers: + - FastTrack + - QuickShip + height: + "$serde_json::private::Number": "25" + isOversized: false + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + serviceLevel: express + validation: + isValid: true + volumetricWeight: + "$serde_json::private::Number": "7.875" + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + baseCosts: + result: "{\"WorldWide\":77.5,\"EcoShip\":21.75,\"SpeedyExpress\":56.25,\"StandardCourier\":28.25,\"FastTrack\":40.5,\"RegularPost\":25,\"GlobalExpress\":87.5,\"QuickShip\":39.75,\"GlobalStandard\":60,\"HeavyHauler\":65}" + carrierCosts: + result: "[{\"cost\":40.5,\"carrier\":\"FastTrack\"},{\"carrier\":\"QuickShip\",\"cost\":39.75}]" + chargableWeight: + result: "12.5" + eligibleCarriers: + result: "[\"FastTrack\",\"QuickShip\"]" + isOversized: + result: "false" + volumetricWeight: + result: "7.875" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + deliveryTimeline: express + destination: domestic + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: ~ + serviceLevel: + id: serviceLevel + input: + deliveryTimeline: express + destination: domestic + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + validation: + isValid: true + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + name: determineServiceLevel + order: + "$serde_json::private::Number": "3" + output: + deliveryTimeline: express + destination: domestic + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + serviceLevel: express + validation: + isValid: true + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: {} + rule: + _id: rule3 + validate: + id: validate + input: + deliveryTimeline: express + destination: domestic + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + name: validatePackage + order: + "$serde_json::private::Number": "1" + output: + deliveryTimeline: express + destination: domestic + height: + "$serde_json::private::Number": "25" + length: + "$serde_json::private::Number": "45" + priorityFactor: cost + validation: + isValid: true + weight: + "$serde_json::private::Number": "12.5" + width: + "$serde_json::private::Number": "35" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: {} + rule: + _id: rule5 diff --git a/core/engine/tests/snapshots/engine__smart-financial-product-matcher_0.snap b/core/engine/tests/snapshots/engine__smart-financial-product-matcher_0.snap new file mode 100644 index 00000000..d4073643 --- /dev/null +++ b/core/engine/tests/snapshots/engine__smart-financial-product-matcher_0.snap @@ -0,0 +1,178 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + recommendationMessage: Start rebuilding your credit with these financial tools. + recommendedProducts: + - secured_credit_card + - basic_checking + - credit_builder_loan +trace: + creditScoreEvaluation: + id: creditScoreEvaluation + input: + customerProfile: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "85000" + creditScore: + "$serde_json::private::Number": "720" + customerId: C12345 + employmentStatus: employed + existingProducts: + - checking_account + financialGoals: + - home_purchase + - retirement_savings + name: Jane Smith + riskTolerance: moderate + name: evaluateCreditScore + order: + "$serde_json::private::Number": "1" + output: + creditCategory: poor + customerProfile: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "85000" + creditScore: + "$serde_json::private::Number": "720" + customerId: C12345 + employmentStatus: employed + existingProducts: + - checking_account + financialGoals: + - home_purchase + - retirement_savings + name: Jane Smith + riskTolerance: moderate + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + creditScore: ~ + rule: + _id: rule4 + "creditScore[i1-1]": "" + incomeEvaluation: + id: incomeEvaluation + input: + creditCategory: poor + customerProfile: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "85000" + creditScore: + "$serde_json::private::Number": "720" + customerId: C12345 + employmentStatus: employed + existingProducts: + - checking_account + financialGoals: + - home_purchase + - retirement_savings + name: Jane Smith + riskTolerance: moderate + name: evaluateIncome + order: + "$serde_json::private::Number": "2" + output: + creditCategory: poor + customerProfile: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "85000" + creditScore: + "$serde_json::private::Number": "720" + customerId: C12345 + employmentStatus: employed + existingProducts: + - checking_account + financialGoals: + - home_purchase + - retirement_savings + name: Jane Smith + riskTolerance: moderate + incomeCategory: low + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + annualIncome: ~ + rule: + _id: rule3 + "annualIncome[i2-1]": "" + input: + id: input + input: ~ + name: customerProfile + order: + "$serde_json::private::Number": "0" + output: + customerProfile: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "85000" + creditScore: + "$serde_json::private::Number": "720" + customerId: C12345 + employmentStatus: employed + existingProducts: + - checking_account + financialGoals: + - home_purchase + - retirement_savings + name: Jane Smith + riskTolerance: moderate + performance: "[perf]" + traceData: ~ + productRecommendation: + id: productRecommendation + input: + creditCategory: poor + customerProfile: + age: + "$serde_json::private::Number": "35" + annualIncome: + "$serde_json::private::Number": "85000" + creditScore: + "$serde_json::private::Number": "720" + customerId: C12345 + employmentStatus: employed + existingProducts: + - checking_account + financialGoals: + - home_purchase + - retirement_savings + name: Jane Smith + riskTolerance: moderate + incomeCategory: low + name: recommendProducts + order: + "$serde_json::private::Number": "3" + output: + recommendationMessage: Start rebuilding your credit with these financial tools. + recommendedProducts: + - secured_credit_card + - basic_checking + - credit_builder_loan + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "4" + reference_map: + creditCategory: poor + incomeCategory: low + rule: + _id: rule5 + "creditCategory[i3-1]": "'poor'" + "incomeCategory[i3-2]": "" diff --git a/core/engine/tests/snapshots/engine__supply-chain-risk_0.snap b/core/engine/tests/snapshots/engine__supply-chain-risk_0.snap new file mode 100644 index 00000000..07ce67e7 --- /dev/null +++ b/core/engine/tests/snapshots/engine__supply-chain-risk_0.snap @@ -0,0 +1,300 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + adjustedRiskScore: + "$serde_json::private::Number": "57" + assessment: + baseRiskCategory: medium + baseRiskScore: + "$serde_json::private::Number": "40" + recommendedAction: Monitor supplier performance and conduct quarterly reviews + finalAssessment: + leadTimeImpact: minor + priorityLevel: medium + riskCategory: medium + geopoliticalFactor: + "$serde_json::private::Number": "1.3" + geopoliticalTensions: true + leadTimeData: + averageDays: + "$serde_json::private::Number": "45" + historicalVariance: + "$serde_json::private::Number": "8" + marketVolatility: medium + marketVolatilityFactor: + "$serde_json::private::Number": "1.1" + supplier: + alternateSourcesCount: + "$serde_json::private::Number": "2" + location: medium_risk_region + name: GlobalTech Supplies Inc. + performanceScore: + "$serde_json::private::Number": "82" + products: + - criticalComponent: true + id: P123 + name: Semiconductor Chip + relationshipDurationMonths: + "$serde_json::private::Number": "36" + supplyCategory: electronics +trace: + geopoliticalRiskCalculation: + id: geopoliticalRiskCalculation + input: + assessment: + baseRiskCategory: medium + baseRiskScore: + "$serde_json::private::Number": "40" + recommendedAction: Monitor supplier performance and conduct quarterly reviews + geopoliticalTensions: true + leadTimeData: + averageDays: + "$serde_json::private::Number": "45" + historicalVariance: + "$serde_json::private::Number": "8" + marketVolatility: medium + supplier: + alternateSourcesCount: + "$serde_json::private::Number": "2" + location: medium_risk_region + name: GlobalTech Supplies Inc. + performanceScore: + "$serde_json::private::Number": "82" + products: + - criticalComponent: true + id: P123 + name: Semiconductor Chip + relationshipDurationMonths: + "$serde_json::private::Number": "36" + supplyCategory: electronics + name: geopoliticalRiskCalculation + order: + "$serde_json::private::Number": "2" + output: + adjustedRiskScore: + "$serde_json::private::Number": "57" + assessment: + baseRiskCategory: medium + baseRiskScore: + "$serde_json::private::Number": "40" + recommendedAction: Monitor supplier performance and conduct quarterly reviews + geopoliticalFactor: + "$serde_json::private::Number": "1.3" + geopoliticalTensions: true + leadTimeData: + averageDays: + "$serde_json::private::Number": "45" + historicalVariance: + "$serde_json::private::Number": "8" + marketVolatility: medium + marketVolatilityFactor: + "$serde_json::private::Number": "1.1" + supplier: + alternateSourcesCount: + "$serde_json::private::Number": "2" + location: medium_risk_region + name: GlobalTech Supplies Inc. + performanceScore: + "$serde_json::private::Number": "82" + products: + - criticalComponent: true + id: P123 + name: Semiconductor Chip + relationshipDurationMonths: + "$serde_json::private::Number": "36" + supplyCategory: electronics + performance: "[perf]" + traceData: + adjustedRiskScore: + result: "57" + geopoliticalFactor: + result: "1.3" + marketVolatilityFactor: + result: "1.1" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + geopoliticalTensions: true + leadTimeData: + averageDays: + "$serde_json::private::Number": "45" + historicalVariance: + "$serde_json::private::Number": "8" + marketVolatility: medium + supplier: + alternateSourcesCount: + "$serde_json::private::Number": "2" + location: medium_risk_region + name: GlobalTech Supplies Inc. + performanceScore: + "$serde_json::private::Number": "82" + products: + - criticalComponent: true + id: P123 + name: Semiconductor Chip + relationshipDurationMonths: + "$serde_json::private::Number": "36" + supplyCategory: electronics + performance: "[perf]" + traceData: ~ + overallRiskAssessment: + id: overallRiskAssessment + input: + adjustedRiskScore: + "$serde_json::private::Number": "57" + assessment: + baseRiskCategory: medium + baseRiskScore: + "$serde_json::private::Number": "40" + recommendedAction: Monitor supplier performance and conduct quarterly reviews + geopoliticalFactor: + "$serde_json::private::Number": "1.3" + geopoliticalTensions: true + leadTimeData: + averageDays: + "$serde_json::private::Number": "45" + historicalVariance: + "$serde_json::private::Number": "8" + marketVolatility: medium + marketVolatilityFactor: + "$serde_json::private::Number": "1.1" + supplier: + alternateSourcesCount: + "$serde_json::private::Number": "2" + location: medium_risk_region + name: GlobalTech Supplies Inc. + performanceScore: + "$serde_json::private::Number": "82" + products: + - criticalComponent: true + id: P123 + name: Semiconductor Chip + relationshipDurationMonths: + "$serde_json::private::Number": "36" + supplyCategory: electronics + name: overallRiskAssessment + order: + "$serde_json::private::Number": "3" + output: + adjustedRiskScore: + "$serde_json::private::Number": "57" + assessment: + baseRiskCategory: medium + baseRiskScore: + "$serde_json::private::Number": "40" + recommendedAction: Monitor supplier performance and conduct quarterly reviews + finalAssessment: + leadTimeImpact: minor + priorityLevel: medium + riskCategory: medium + geopoliticalFactor: + "$serde_json::private::Number": "1.3" + geopoliticalTensions: true + leadTimeData: + averageDays: + "$serde_json::private::Number": "45" + historicalVariance: + "$serde_json::private::Number": "8" + marketVolatility: medium + marketVolatilityFactor: + "$serde_json::private::Number": "1.1" + supplier: + alternateSourcesCount: + "$serde_json::private::Number": "2" + location: medium_risk_region + name: GlobalTech Supplies Inc. + performanceScore: + "$serde_json::private::Number": "82" + products: + - criticalComponent: true + id: P123 + name: Semiconductor Chip + relationshipDurationMonths: + "$serde_json::private::Number": "36" + supplyCategory: electronics + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + adjustedRiskScore: + "$serde_json::private::Number": "57" + rule: + _id: finalRule3 + "adjustedRiskScore[adjustedRiskScore]": ">= 40" + supplierRiskEvaluation: + id: supplierRiskEvaluation + input: + geopoliticalTensions: true + leadTimeData: + averageDays: + "$serde_json::private::Number": "45" + historicalVariance: + "$serde_json::private::Number": "8" + marketVolatility: medium + supplier: + alternateSourcesCount: + "$serde_json::private::Number": "2" + location: medium_risk_region + name: GlobalTech Supplies Inc. + performanceScore: + "$serde_json::private::Number": "82" + products: + - criticalComponent: true + id: P123 + name: Semiconductor Chip + relationshipDurationMonths: + "$serde_json::private::Number": "36" + supplyCategory: electronics + name: supplierRiskEvaluation + order: + "$serde_json::private::Number": "1" + output: + assessment: + baseRiskCategory: medium + baseRiskScore: + "$serde_json::private::Number": "40" + recommendedAction: Monitor supplier performance and conduct quarterly reviews + geopoliticalTensions: true + leadTimeData: + averageDays: + "$serde_json::private::Number": "45" + historicalVariance: + "$serde_json::private::Number": "8" + marketVolatility: medium + supplier: + alternateSourcesCount: + "$serde_json::private::Number": "2" + location: medium_risk_region + name: GlobalTech Supplies Inc. + performanceScore: + "$serde_json::private::Number": "82" + products: + - criticalComponent: true + id: P123 + name: Semiconductor Chip + relationshipDurationMonths: + "$serde_json::private::Number": "36" + supplyCategory: electronics + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + supplier.alternateSourcesCount: + "$serde_json::private::Number": "2" + supplier.location: medium_risk_region + supplier.performanceScore: + "$serde_json::private::Number": "82" + rule: + _id: rule4 + "supplier.alternateSourcesCount[alternativeSources]": "" + "supplier.location[supplierLocation]": "'medium_risk_region'" + "supplier.performanceScore[historicalPerformance]": ">= 80" diff --git a/core/engine/tests/snapshots/engine__table-loop_0.snap b/core/engine/tests/snapshots/engine__table-loop_0.snap new file mode 100644 index 00000000..039617a7 --- /dev/null +++ b/core/engine/tests/snapshots/engine__table-loop_0.snap @@ -0,0 +1,51 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + res: + - world: bar + - world: error +trace: + 668e8acb-5b42-4bd6-b399-cbe790df7532: + id: 668e8acb-5b42-4bd6-b399-cbe790df7532 + input: + items: + - hello: foo + - hello: koo + name: decisionTable1 + order: + "$serde_json::private::Number": "1" + output: + res: + - world: bar + - world: error + performance: "[perf]" + traceData: + - index: + "$serde_json::private::Number": "0" + reference_map: + hello: foo + rule: + _id: 78f3629d-f7eb-4fdb-94b1-c4be9f7bd534 + "hello[6d27354e-56ff-4b25-9160-5fb428c98a5d]": "\"foo\"" + - index: + "$serde_json::private::Number": "1" + reference_map: + hello: koo + rule: + _id: 582b14c8-df87-4c83-8954-4904dc811a98 + "hello[6d27354e-56ff-4b25-9160-5fb428c98a5d]": "" + da3ed838-ab74-4f55-a703-2d1b7e507722: + id: da3ed838-ab74-4f55-a703-2d1b7e507722 + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + items: + - hello: foo + - hello: koo + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__tax-exemption_0.snap b/core/engine/tests/snapshots/engine__tax-exemption_0.snap new file mode 100644 index 00000000..542c1d0b --- /dev/null +++ b/core/engine/tests/snapshots/engine__tax-exemption_0.snap @@ -0,0 +1,161 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + annualRevenue: + "$serde_json::private::Number": "175000" + charitableActivitiesPercentage: + "$serde_json::private::Number": "92.3" + organizationType: nonprofit + politicalActivity: false + publicSupportPercentage: + "$serde_json::private::Number": "45.7" + result: + annualFilingRequirement: 990-EZ + classification: 501(c)(3) + effectiveDate: 2025-03-20 + explanation: Public charity with substantial public support + publicDisclosureRequired: true + status: Exempt +trace: + dt1: + id: dt1 + input: + annualRevenue: + "$serde_json::private::Number": "175000" + charitableActivitiesPercentage: + "$serde_json::private::Number": "92.3" + organizationType: nonprofit + politicalActivity: false + publicSupportPercentage: + "$serde_json::private::Number": "45.7" + name: taxExemptionEvaluation + order: + "$serde_json::private::Number": "1" + output: + annualRevenue: + "$serde_json::private::Number": "175000" + charitableActivitiesPercentage: + "$serde_json::private::Number": "92.3" + organizationType: nonprofit + politicalActivity: false + publicSupportPercentage: + "$serde_json::private::Number": "45.7" + result: + classification: 501(c)(3) + explanation: Public charity with substantial public support + status: Exempt + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + charitableActivitiesPercentage: + "$serde_json::private::Number": "92.3" + organizationType: nonprofit + politicalActivity: false + publicSupportPercentage: + "$serde_json::private::Number": "45.7" + rule: + _description: 501(c)(3) Nonprofit with high public support + _id: r1-3 + "charitableActivitiesPercentage[i1-3]": ">= 85" + "organizationType[i1-1]": "'nonprofit'" + "politicalActivity[i1-2]": "false" + "publicSupportPercentage[i1-4]": ">= 33.3" + ex1: + id: ex1 + input: + annualRevenue: + "$serde_json::private::Number": "175000" + charitableActivitiesPercentage: + "$serde_json::private::Number": "92.3" + organizationType: nonprofit + politicalActivity: false + publicSupportPercentage: + "$serde_json::private::Number": "45.7" + result: + classification: 501(c)(3) + explanation: Public charity with substantial public support + status: Exempt + name: exemptRequirements + order: + "$serde_json::private::Number": "3" + output: + annualRevenue: + "$serde_json::private::Number": "175000" + charitableActivitiesPercentage: + "$serde_json::private::Number": "92.3" + organizationType: nonprofit + politicalActivity: false + publicSupportPercentage: + "$serde_json::private::Number": "45.7" + result: + annualFilingRequirement: 990-EZ + classification: 501(c)(3) + effectiveDate: 2025-03-20 + explanation: Public charity with substantial public support + publicDisclosureRequired: true + status: Exempt + performance: "[perf]" + traceData: + result.annualFilingRequirement: + result: "\"990-EZ\"" + result.effectiveDate: + result: "\"2025-03-20\"" + result.publicDisclosureRequired: + result: "true" + ip1: + id: ip1 + input: ~ + name: organizationRequest + order: + "$serde_json::private::Number": "0" + output: + annualRevenue: + "$serde_json::private::Number": "175000" + charitableActivitiesPercentage: + "$serde_json::private::Number": "92.3" + organizationType: nonprofit + politicalActivity: false + publicSupportPercentage: + "$serde_json::private::Number": "45.7" + performance: "[perf]" + traceData: ~ + sw1: + id: sw1 + input: + annualRevenue: + "$serde_json::private::Number": "175000" + charitableActivitiesPercentage: + "$serde_json::private::Number": "92.3" + organizationType: nonprofit + politicalActivity: false + publicSupportPercentage: + "$serde_json::private::Number": "45.7" + result: + classification: 501(c)(3) + explanation: Public charity with substantial public support + status: Exempt + name: requiresAdditionalClassification + order: + "$serde_json::private::Number": "2" + output: + annualRevenue: + "$serde_json::private::Number": "175000" + charitableActivitiesPercentage: + "$serde_json::private::Number": "92.3" + organizationType: nonprofit + politicalActivity: false + publicSupportPercentage: + "$serde_json::private::Number": "45.7" + result: + classification: 501(c)(3) + explanation: Public charity with substantial public support + status: Exempt + performance: "[perf]" + traceData: + statements: + - id: s1-1 diff --git a/core/engine/tests/snapshots/engine__traffic-violation-penalty-calculator_0.snap b/core/engine/tests/snapshots/engine__traffic-violation-penalty-calculator_0.snap new file mode 100644 index 00000000..c119b577 --- /dev/null +++ b/core/engine/tests/snapshots/engine__traffic-violation-penalty-calculator_0.snap @@ -0,0 +1,292 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + assessment: + base_fine: + "$serde_json::private::Number": "150" + base_points: + "$serde_json::private::Number": "3" + final_fine: + "$serde_json::private::Number": "180" + final_points: + "$serde_json::private::Number": "3" + license_suspension_recommended: false + payment_deadline_days: + "$serde_json::private::Number": "30" + risk_level: medium + severity: moderate + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding +trace: + final_assessment: + id: final_assessment + input: + assessment: + base_fine: + "$serde_json::private::Number": "150" + base_points: + "$serde_json::private::Number": "3" + final_fine: + "$serde_json::private::Number": "180" + final_points: + "$serde_json::private::Number": "3" + license_suspension_recommended: false + severity: moderate + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding + name: finalize_assessment + order: + "$serde_json::private::Number": "3" + output: + assessment: + base_fine: + "$serde_json::private::Number": "150" + base_points: + "$serde_json::private::Number": "3" + final_fine: + "$serde_json::private::Number": "180" + final_points: + "$serde_json::private::Number": "3" + license_suspension_recommended: false + severity: moderate + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding + performance: "[perf]" + traceData: + assessment.final_fine: + result: "180" + assessment.final_points: + result: "3" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding + performance: "[perf]" + traceData: ~ + penalty_calculation: + id: penalty_calculation + input: + assessment: + base_fine: + "$serde_json::private::Number": "150" + base_points: + "$serde_json::private::Number": "3" + severity: moderate + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding + name: calculate_penalty + order: + "$serde_json::private::Number": "2" + output: + assessment: + base_fine: + "$serde_json::private::Number": "150" + base_points: + "$serde_json::private::Number": "3" + final_fine: + "$serde_json::private::Number": "180" + final_points: + "$serde_json::private::Number": "3" + license_suspension_recommended: false + severity: moderate + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + assessment.severity: moderate + driver.previous_violations: + "$serde_json::private::Number": "1" + violation.in_school_zone: true + rule: + _id: pc4 + "assessment.severity[i1]": "'moderate'" + "driver.previous_violations[i2]": "" + "violation.in_school_zone[i3]": "true" + risk_assessment: + id: risk_assessment + input: + assessment: + base_fine: + "$serde_json::private::Number": "150" + base_points: + "$serde_json::private::Number": "3" + final_fine: + "$serde_json::private::Number": "180" + final_points: + "$serde_json::private::Number": "3" + license_suspension_recommended: false + severity: moderate + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding + name: assess_risk_and_deadlines + order: + "$serde_json::private::Number": "4" + output: + assessment: + base_fine: + "$serde_json::private::Number": "150" + base_points: + "$serde_json::private::Number": "3" + final_fine: + "$serde_json::private::Number": "180" + final_points: + "$serde_json::private::Number": "3" + license_suspension_recommended: false + payment_deadline_days: + "$serde_json::private::Number": "30" + risk_level: medium + severity: moderate + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + assessment.final_points: + "$serde_json::private::Number": "3" + assessment.severity: moderate + rule: + _id: ra3 + "assessment.final_points[i1]": ">= 3" + "assessment.severity[i2]": "'moderate'" + violation_classification: + id: violation_classification + input: + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding + name: classify_violation + order: + "$serde_json::private::Number": "1" + output: + assessment: + base_fine: + "$serde_json::private::Number": "150" + base_points: + "$serde_json::private::Number": "3" + severity: moderate + driver: + license_issue_date: 2020-06-15 + license_number: DL123456789 + previous_violations: + "$serde_json::private::Number": "1" + violation: + date: "2025-03-15T14:30:00Z" + in_school_zone: true + location: Main St & 5th Ave + speed_over_limit: + "$serde_json::private::Number": "25" + type: speeding + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + violation.speed_over_limit: + "$serde_json::private::Number": "25" + violation.type: speeding + rule: + _id: rule2 + "violation.speed_over_limit[i2]": "> 15" + "violation.type[i1]": "'speeding'" diff --git a/core/engine/tests/snapshots/engine__transaction-compliance-classifier_0.snap b/core/engine/tests/snapshots/engine__transaction-compliance-classifier_0.snap new file mode 100644 index 00000000..c3d3d378 --- /dev/null +++ b/core/engine/tests/snapshots/engine__transaction-compliance-classifier_0.snap @@ -0,0 +1,605 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + has_compliance_flags: false + report_instructions: File FinCEN Form 112 within 24 hours + reporting_deadline: + "$serde_json::private::Number": "1743330600" + reporting_status: urgent_filing_required + requires_immediate_filing: true +trace: + compliance_flags: + id: compliance_flags + input: + amount_score: + "$serde_json::private::Number": "15" + base_risk_score: + "$serde_json::private::Number": "0" + classification: + priority: high_priority + report_type: CTR + compliance: + requires_review: true + review_reason: Medium risk score with high priority requires review + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + customer_score: + "$serde_json::private::Number": "0" + priority_score: + "$serde_json::private::Number": "25" + reporting: + days_to_report: + "$serde_json::private::Number": "15" + form_name: FinCEN Form 112 + risk: + jurisdiction_score: + "$serde_json::private::Number": "15" + total_risk_score: + "$serde_json::private::Number": "55" + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + transaction_history_score: + "$serde_json::private::Number": "0" + name: identify_compliance_issues + order: + "$serde_json::private::Number": "5" + output: + amount_score: + "$serde_json::private::Number": "15" + base_risk_score: + "$serde_json::private::Number": "0" + classification: + priority: high_priority + report_type: CTR + compliance: + flags: [] + requires_review: true + review_reason: Medium risk score with high priority requires review + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + customer_score: + "$serde_json::private::Number": "0" + priority_score: + "$serde_json::private::Number": "25" + reporting: + days_to_report: + "$serde_json::private::Number": "15" + form_name: FinCEN Form 112 + risk: + jurisdiction_score: + "$serde_json::private::Number": "15" + total_risk_score: + "$serde_json::private::Number": "55" + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + transaction_history_score: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: [] + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + performance: "[perf]" + traceData: ~ + jurisdiction_rules: + id: jurisdiction_rules + input: + classification: + priority: high_priority + report_type: CTR + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + name: apply_jurisdiction_rules + order: + "$serde_json::private::Number": "2" + output: + classification: + priority: high_priority + report_type: CTR + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + reporting: + days_to_report: + "$serde_json::private::Number": "15" + form_name: FinCEN Form 112 + risk: + jurisdiction_score: + "$serde_json::private::Number": "15" + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + classification.report_type: CTR + customer.jurisdiction: US + rule: + _id: r2-1 + "classification.report_type[i2-2]": "'CTR'" + "customer.jurisdiction[i2-1]": "'US'" + reporting_requirements: + id: reporting_requirements + input: + amount_score: + "$serde_json::private::Number": "15" + base_risk_score: + "$serde_json::private::Number": "0" + classification: + priority: high_priority + report_type: CTR + compliance: + flags: [] + requires_review: true + review_reason: Medium risk score with high priority requires review + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + customer_score: + "$serde_json::private::Number": "0" + priority_score: + "$serde_json::private::Number": "25" + reporting: + days_to_report: + "$serde_json::private::Number": "15" + form_name: FinCEN Form 112 + risk: + jurisdiction_score: + "$serde_json::private::Number": "15" + total_risk_score: + "$serde_json::private::Number": "55" + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + transaction_history_score: + "$serde_json::private::Number": "0" + name: determine_reporting_requirements + order: + "$serde_json::private::Number": "6" + output: + has_compliance_flags: false + report_instructions: File FinCEN Form 112 within 24 hours + reporting_deadline: + "$serde_json::private::Number": "1743330600" + reporting_status: urgent_filing_required + requires_immediate_filing: true + performance: "[perf]" + traceData: + has_compliance_flags: + result: "false" + report_instructions: + result: "\"File FinCEN Form 112 within 24 hours\"" + reporting_deadline: + result: "1743330600" + reporting_status: + result: "\"urgent_filing_required\"" + requires_immediate_filing: + result: "true" + risk_assessment: + id: risk_assessment + input: + classification: + priority: high_priority + report_type: CTR + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + reporting: + days_to_report: + "$serde_json::private::Number": "15" + form_name: FinCEN Form 112 + risk: + jurisdiction_score: + "$serde_json::private::Number": "15" + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + name: calculate_risk_score + order: + "$serde_json::private::Number": "3" + output: + amount_score: + "$serde_json::private::Number": "15" + base_risk_score: + "$serde_json::private::Number": "0" + classification: + priority: high_priority + report_type: CTR + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + customer_score: + "$serde_json::private::Number": "0" + priority_score: + "$serde_json::private::Number": "25" + reporting: + days_to_report: + "$serde_json::private::Number": "15" + form_name: FinCEN Form 112 + risk: + jurisdiction_score: + "$serde_json::private::Number": "15" + total_risk_score: + "$serde_json::private::Number": "55" + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + transaction_history_score: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + amount_score: + result: "15" + base_risk_score: + result: "0" + customer_score: + result: "0" + priority_score: + result: "25" + total_risk_score: + result: "55" + transaction_history_score: + result: "0" + threshold_checks: + id: threshold_checks + input: + amount_score: + "$serde_json::private::Number": "15" + base_risk_score: + "$serde_json::private::Number": "0" + classification: + priority: high_priority + report_type: CTR + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + customer_score: + "$serde_json::private::Number": "0" + priority_score: + "$serde_json::private::Number": "25" + reporting: + days_to_report: + "$serde_json::private::Number": "15" + form_name: FinCEN Form 112 + risk: + jurisdiction_score: + "$serde_json::private::Number": "15" + total_risk_score: + "$serde_json::private::Number": "55" + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + transaction_history_score: + "$serde_json::private::Number": "0" + name: regulatory_thresholds + order: + "$serde_json::private::Number": "4" + output: + amount_score: + "$serde_json::private::Number": "15" + base_risk_score: + "$serde_json::private::Number": "0" + classification: + priority: high_priority + report_type: CTR + compliance: + requires_review: true + review_reason: Medium risk score with high priority requires review + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + customer_score: + "$serde_json::private::Number": "0" + priority_score: + "$serde_json::private::Number": "25" + reporting: + days_to_report: + "$serde_json::private::Number": "15" + form_name: FinCEN Form 112 + risk: + jurisdiction_score: + "$serde_json::private::Number": "15" + total_risk_score: + "$serde_json::private::Number": "55" + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + transaction_history_score: + "$serde_json::private::Number": "0" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + classification.priority: high_priority + total_risk_score: + "$serde_json::private::Number": "55" + rule: + _id: r3-3 + "classification.priority[i3-2]": "'high_priority'" + "total_risk_score[i3-1]": "[40..60]" + transaction_type: + id: transaction_type + input: + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + name: classify_transaction + order: + "$serde_json::private::Number": "1" + output: + classification: + priority: high_priority + report_type: CTR + customer: + account_opening_date: 2020-01-15 + high_risk: false + id: CUST98765 + jurisdiction: US + kyc_verified: true + name: Acme Corporation + normal_activity_patterns: + - cash_deposit + - domestic_wire + - check_deposit + risk_category: medium + suspicious_activity_count: + "$serde_json::private::Number": "0" + type: business + transaction: + amount: + "$serde_json::private::Number": "15000" + currency: USD + date: "2025-03-15T10:30:00Z" + description: Business cash deposit + high_risk_country: false + id: TX123456789 + structuring_suspected: false + type: cash_deposit + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "0" + reference_map: + transaction.amount: + "$serde_json::private::Number": "15000" + transaction.type: cash_deposit + rule: + _id: r1-1 + "transaction.amount[i1-2]": "> 10000" + "transaction.type[i1-1]": "'cash_deposit'" diff --git a/core/engine/tests/snapshots/engine__vehicle-claims-resolution_0.snap b/core/engine/tests/snapshots/engine__vehicle-claims-resolution_0.snap new file mode 100644 index 00000000..ce4695cb --- /dev/null +++ b/core/engine/tests/snapshots/engine__vehicle-claims-resolution_0.snap @@ -0,0 +1,205 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + assessment: + damageLevel: severe + isTotalLoss: false + claim: + damagePercentage: + "$serde_json::private::Number": "65" + id: CL-20250318-001 + parts: + availability: available + status: limited + recommendation: + explanation: Severe damage with obtainable parts; repair recommended + method: repair + vehicle: + ageYears: + "$serde_json::private::Number": "10" + make: Toyota + model: Camry + year: + "$serde_json::private::Number": "2015" +trace: + assessDamage: + id: assessDamage + input: + claim: + damagePercentage: + "$serde_json::private::Number": "65" + id: CL-20250318-001 + parts: + status: limited + vehicle: + ageYears: + "$serde_json::private::Number": "10" + make: Toyota + model: Camry + year: + "$serde_json::private::Number": "2015" + name: assessDamage + order: + "$serde_json::private::Number": "1" + output: + assessment: + damageLevel: severe + isTotalLoss: false + claim: + damagePercentage: + "$serde_json::private::Number": "65" + id: CL-20250318-001 + parts: + status: limited + vehicle: + ageYears: + "$serde_json::private::Number": "10" + make: Toyota + model: Camry + year: + "$serde_json::private::Number": "2015" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + claim.damagePercentage: + "$serde_json::private::Number": "65" + rule: + _id: rule2 + "claim.damagePercentage[i1]": ">= 60" + checkPartsAvailability: + id: checkPartsAvailability + input: + assessment: + damageLevel: severe + isTotalLoss: false + claim: + damagePercentage: + "$serde_json::private::Number": "65" + id: CL-20250318-001 + parts: + status: limited + vehicle: + ageYears: + "$serde_json::private::Number": "10" + make: Toyota + model: Camry + year: + "$serde_json::private::Number": "2015" + name: checkPartsAvailability + order: + "$serde_json::private::Number": "2" + output: + assessment: + damageLevel: severe + isTotalLoss: false + claim: + damagePercentage: + "$serde_json::private::Number": "65" + id: CL-20250318-001 + parts: + availability: available + status: limited + vehicle: + ageYears: + "$serde_json::private::Number": "10" + make: Toyota + model: Camry + year: + "$serde_json::private::Number": "2015" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + parts.status: limited + vehicle.ageYears: + "$serde_json::private::Number": "10" + rule: + _id: rule4 + "parts.status[i2]": "" + "vehicle.ageYears[i1]": "<= 10" + determineRepairMethod: + id: determineRepairMethod + input: + assessment: + damageLevel: severe + isTotalLoss: false + claim: + damagePercentage: + "$serde_json::private::Number": "65" + id: CL-20250318-001 + parts: + availability: available + status: limited + vehicle: + ageYears: + "$serde_json::private::Number": "10" + make: Toyota + model: Camry + year: + "$serde_json::private::Number": "2015" + name: determineRepairMethod + order: + "$serde_json::private::Number": "3" + output: + assessment: + damageLevel: severe + isTotalLoss: false + claim: + damagePercentage: + "$serde_json::private::Number": "65" + id: CL-20250318-001 + parts: + availability: available + status: limited + recommendation: + explanation: Severe damage with obtainable parts; repair recommended + method: repair + vehicle: + ageYears: + "$serde_json::private::Number": "10" + make: Toyota + model: Camry + year: + "$serde_json::private::Number": "2015" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "3" + reference_map: + assessment.damageLevel: severe + parts.availability: available + vehicle.ageYears: + "$serde_json::private::Number": "10" + rule: + _id: rule4 + "assessment.damageLevel[i1]": "'severe'" + "parts.availability[i2]": "'delayed', 'available'" + "vehicle.ageYears[i3]": "" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + claim: + damagePercentage: + "$serde_json::private::Number": "65" + id: CL-20250318-001 + parts: + status: limited + vehicle: + ageYears: + "$serde_json::private::Number": "10" + make: Toyota + model: Camry + year: + "$serde_json::private::Number": "2015" + performance: "[perf]" + traceData: ~ diff --git a/core/engine/tests/snapshots/engine__warehouse-cross-docking_0.snap b/core/engine/tests/snapshots/engine__warehouse-cross-docking_0.snap new file mode 100644 index 00000000..f06192e7 --- /dev/null +++ b/core/engine/tests/snapshots/engine__warehouse-cross-docking_0.snap @@ -0,0 +1,379 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + crossDockDecision: cross-dock + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + decisionReason: Matching orders available within 48 hours + dockingBay: Bay-E4 + estimatedProcessingTime: + "$serde_json::private::Number": "30" + hasMatchingOutboundOrders: true + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + priority: normal + timeDifferenceHours: + "$serde_json::private::Number": "23" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + warehouseCapacityPercentage: + "$serde_json::private::Number": "75" +trace: + dt1: + id: dt1 + input: + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + hasMatchingOutboundOrders: true + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + timeDifferenceHours: + "$serde_json::private::Number": "23" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + warehouseCapacityPercentage: + "$serde_json::private::Number": "75" + name: crossDockingDecision + order: + "$serde_json::private::Number": "2" + output: + crossDockDecision: cross-dock + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + decisionReason: Matching orders available within 48 hours + hasMatchingOutboundOrders: true + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + timeDifferenceHours: + "$serde_json::private::Number": "23" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + warehouseCapacityPercentage: + "$serde_json::private::Number": "75" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + hasMatchingOutboundOrders: true + timeDifferenceHours: + "$serde_json::private::Number": "23" + warehouseCapacityPercentage: + "$serde_json::private::Number": "75" + rule: + _id: r1-2 + "hasMatchingOutboundOrders[i1-1]": "true" + "timeDifferenceHours[i1-2]": "[0..48]" + "warehouseCapacityPercentage[i1-3]": "<= 80" + ex1: + id: ex1 + input: + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + name: calculateMetrics + order: + "$serde_json::private::Number": "1" + output: + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + hasMatchingOutboundOrders: true + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + timeDifferenceHours: + "$serde_json::private::Number": "23" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + warehouseCapacityPercentage: + "$serde_json::private::Number": "75" + performance: "[perf]" + traceData: + hasMatchingOutboundOrders: + result: "true" + timeDifferenceHours: + result: "23" + warehouseCapacityPercentage: + result: "75" + ex2: + id: ex2 + input: + crossDockDecision: cross-dock + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + decisionReason: Matching orders available within 48 hours + hasMatchingOutboundOrders: true + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + timeDifferenceHours: + "$serde_json::private::Number": "23" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + warehouseCapacityPercentage: + "$serde_json::private::Number": "75" + name: assignCrossDockingDetails + order: + "$serde_json::private::Number": "4" + output: + crossDockDecision: cross-dock + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + decisionReason: Matching orders available within 48 hours + dockingBay: Bay-E4 + estimatedProcessingTime: + "$serde_json::private::Number": "30" + hasMatchingOutboundOrders: true + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + priority: normal + timeDifferenceHours: + "$serde_json::private::Number": "23" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + warehouseCapacityPercentage: + "$serde_json::private::Number": "75" + performance: "[perf]" + traceData: + dockingBay: + result: "\"Bay-E4\"" + estimatedProcessingTime: + result: "30" + priority: + result: "\"normal\"" + ip1: + id: ip1 + input: ~ + name: shipmentRequest + order: + "$serde_json::private::Number": "0" + output: + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + performance: "[perf]" + traceData: ~ + sw1: + id: sw1 + input: + crossDockDecision: cross-dock + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + decisionReason: Matching orders available within 48 hours + hasMatchingOutboundOrders: true + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + timeDifferenceHours: + "$serde_json::private::Number": "23" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + warehouseCapacityPercentage: + "$serde_json::private::Number": "75" + name: handleCrossDocking + order: + "$serde_json::private::Number": "3" + output: + crossDockDecision: cross-dock + crossDockingBayAssignment: Bay-E4 + currentStorageUsed: + "$serde_json::private::Number": "7500" + decisionReason: Matching orders available within 48 hours + hasMatchingOutboundOrders: true + inboundShipmentId: IN-12345 + inboundShipmentItems: + - category: Electronics + quantity: + "$serde_json::private::Number": "50" + sku: ITEM-001 + - category: Home Goods + quantity: + "$serde_json::private::Number": "30" + sku: ITEM-002 + inboundShipmentTime: "2025-03-19T10:00:00Z" + matchingOutboundOrders: + - customerPriority: standard + destinationZone: East + orderId: ORD-789 + - customerPriority: premium + destinationZone: East + orderId: ORD-790 + outboundShipmentTime: "2025-03-20T09:00:00Z" + timeDifferenceHours: + "$serde_json::private::Number": "23" + totalStorageCapacity: + "$serde_json::private::Number": "10000" + warehouseCapacityPercentage: + "$serde_json::private::Number": "75" + performance: "[perf]" + traceData: + statements: + - id: s1-1 diff --git a/core/engine/tests/snapshots/engine__warehouse-storage-location_0.snap b/core/engine/tests/snapshots/engine__warehouse-storage-location_0.snap new file mode 100644 index 00000000..1ea410b5 --- /dev/null +++ b/core/engine/tests/snapshots/engine__warehouse-storage-location_0.snap @@ -0,0 +1,327 @@ +--- +source: core/engine/tests/engine.rs +expression: serialized_result +--- +performance: "[perf]" +result: + allocatedLocation: prime-picking-area-pallet-rack-bottom + allocation: + priority: + "$serde_json::private::Number": "3" + storageType: pallet-rack-bottom + warehouseZone: prime-picking-area + classification: + fastMoving: true + volumeCategory: medium-volume + pickingEfficiencyScore: + "$serde_json::private::Number": "7" + product: + dimensions: + height: + "$serde_json::private::Number": "10" + length: + "$serde_json::private::Number": "40" + unit: cm + width: + "$serde_json::private::Number": "30" + fragilityScore: + "$serde_json::private::Number": "4" + hazardous: false + id: PRD-12345 + monthlyUnits: + "$serde_json::private::Number": "2500" + name: Gaming Laptop XZ5000 + picksPerDay: + "$serde_json::private::Number": "12" + specialHandling: false + turnoverRate: + "$serde_json::private::Number": "0.65" + weight: + unit: kg + value: + "$serde_json::private::Number": "3.5" + recommendedQuantity: + "$serde_json::private::Number": "1250" + replenishmentFrequency: weekly +trace: + finalAllocation: + id: finalAllocation + input: + allocation: + priority: + "$serde_json::private::Number": "3" + storageType: pallet-rack-bottom + warehouseZone: prime-picking-area + classification: + fastMoving: true + volumeCategory: medium-volume + product: + dimensions: + height: + "$serde_json::private::Number": "10" + length: + "$serde_json::private::Number": "40" + unit: cm + width: + "$serde_json::private::Number": "30" + fragilityScore: + "$serde_json::private::Number": "4" + hazardous: false + id: PRD-12345 + monthlyUnits: + "$serde_json::private::Number": "2500" + name: Gaming Laptop XZ5000 + picksPerDay: + "$serde_json::private::Number": "12" + specialHandling: false + turnoverRate: + "$serde_json::private::Number": "0.65" + weight: + unit: kg + value: + "$serde_json::private::Number": "3.5" + name: finalizeAllocation + order: + "$serde_json::private::Number": "3" + output: + allocatedLocation: prime-picking-area-pallet-rack-bottom + allocation: + priority: + "$serde_json::private::Number": "3" + storageType: pallet-rack-bottom + warehouseZone: prime-picking-area + classification: + fastMoving: true + volumeCategory: medium-volume + pickingEfficiencyScore: + "$serde_json::private::Number": "7" + product: + dimensions: + height: + "$serde_json::private::Number": "10" + length: + "$serde_json::private::Number": "40" + unit: cm + width: + "$serde_json::private::Number": "30" + fragilityScore: + "$serde_json::private::Number": "4" + hazardous: false + id: PRD-12345 + monthlyUnits: + "$serde_json::private::Number": "2500" + name: Gaming Laptop XZ5000 + picksPerDay: + "$serde_json::private::Number": "12" + specialHandling: false + turnoverRate: + "$serde_json::private::Number": "0.65" + weight: + unit: kg + value: + "$serde_json::private::Number": "3.5" + recommendedQuantity: + "$serde_json::private::Number": "1250" + replenishmentFrequency: weekly + performance: "[perf]" + traceData: + allocatedLocation: + result: "\"prime-picking-area-pallet-rack-bottom\"" + pickingEfficiencyScore: + result: "7" + recommendedQuantity: + result: "1250" + replenishmentFrequency: + result: "\"weekly\"" + input: + id: input + input: ~ + name: request + order: + "$serde_json::private::Number": "0" + output: + product: + dimensions: + height: + "$serde_json::private::Number": "10" + length: + "$serde_json::private::Number": "40" + unit: cm + width: + "$serde_json::private::Number": "30" + fragilityScore: + "$serde_json::private::Number": "4" + hazardous: false + id: PRD-12345 + monthlyUnits: + "$serde_json::private::Number": "2500" + name: Gaming Laptop XZ5000 + picksPerDay: + "$serde_json::private::Number": "12" + specialHandling: false + turnoverRate: + "$serde_json::private::Number": "0.65" + weight: + unit: kg + value: + "$serde_json::private::Number": "3.5" + performance: "[perf]" + traceData: ~ + locationAssignment: + id: locationAssignment + input: + classification: + fastMoving: true + volumeCategory: medium-volume + product: + dimensions: + height: + "$serde_json::private::Number": "10" + length: + "$serde_json::private::Number": "40" + unit: cm + width: + "$serde_json::private::Number": "30" + fragilityScore: + "$serde_json::private::Number": "4" + hazardous: false + id: PRD-12345 + monthlyUnits: + "$serde_json::private::Number": "2500" + name: Gaming Laptop XZ5000 + picksPerDay: + "$serde_json::private::Number": "12" + specialHandling: false + turnoverRate: + "$serde_json::private::Number": "0.65" + weight: + unit: kg + value: + "$serde_json::private::Number": "3.5" + name: assignLocation + order: + "$serde_json::private::Number": "2" + output: + allocation: + priority: + "$serde_json::private::Number": "3" + storageType: pallet-rack-bottom + warehouseZone: prime-picking-area + classification: + fastMoving: true + volumeCategory: medium-volume + product: + dimensions: + height: + "$serde_json::private::Number": "10" + length: + "$serde_json::private::Number": "40" + unit: cm + width: + "$serde_json::private::Number": "30" + fragilityScore: + "$serde_json::private::Number": "4" + hazardous: false + id: PRD-12345 + monthlyUnits: + "$serde_json::private::Number": "2500" + name: Gaming Laptop XZ5000 + picksPerDay: + "$serde_json::private::Number": "12" + specialHandling: false + turnoverRate: + "$serde_json::private::Number": "0.65" + weight: + unit: kg + value: + "$serde_json::private::Number": "3.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "2" + reference_map: + classification.fastMoving: true + classification.volumeCategory: medium-volume + product.fragilityScore: + "$serde_json::private::Number": "4" + rule: + _id: rule3 + "classification.fastMoving[i2]": "true" + "classification.volumeCategory[i1]": "'medium-volume'" + "product.fragilityScore[i3]": "> 2" + productClassification: + id: productClassification + input: + product: + dimensions: + height: + "$serde_json::private::Number": "10" + length: + "$serde_json::private::Number": "40" + unit: cm + width: + "$serde_json::private::Number": "30" + fragilityScore: + "$serde_json::private::Number": "4" + hazardous: false + id: PRD-12345 + monthlyUnits: + "$serde_json::private::Number": "2500" + name: Gaming Laptop XZ5000 + picksPerDay: + "$serde_json::private::Number": "12" + specialHandling: false + turnoverRate: + "$serde_json::private::Number": "0.65" + weight: + unit: kg + value: + "$serde_json::private::Number": "3.5" + name: classifyProduct + order: + "$serde_json::private::Number": "1" + output: + classification: + fastMoving: true + volumeCategory: medium-volume + product: + dimensions: + height: + "$serde_json::private::Number": "10" + length: + "$serde_json::private::Number": "40" + unit: cm + width: + "$serde_json::private::Number": "30" + fragilityScore: + "$serde_json::private::Number": "4" + hazardous: false + id: PRD-12345 + monthlyUnits: + "$serde_json::private::Number": "2500" + name: Gaming Laptop XZ5000 + picksPerDay: + "$serde_json::private::Number": "12" + specialHandling: false + turnoverRate: + "$serde_json::private::Number": "0.65" + weight: + unit: kg + value: + "$serde_json::private::Number": "3.5" + performance: "[perf]" + traceData: + index: + "$serde_json::private::Number": "1" + reference_map: + product.monthlyUnits: + "$serde_json::private::Number": "2500" + product.picksPerDay: + "$serde_json::private::Number": "12" + product.turnoverRate: + "$serde_json::private::Number": "0.65" + rule: + _id: rule2 + "product.monthlyUnits[i1]": "> 1000" + "product.picksPerDay[i3]": "> 10" + "product.turnoverRate[i2]": "> 0.5" diff --git a/test-data/graphs/account-dormancy-management.json b/test-data/graphs/account-dormancy-management.json new file mode 100644 index 00000000..75a448ba --- /dev/null +++ b/test-data/graphs/account-dormancy-management.json @@ -0,0 +1,245 @@ +{ + "tests": [ + { + "input": { + "accountId": "ACC98765432", + "accountType": "savings", + "customerTier": "premium", + "lastActivityDate": "2024-11-15", + "dormancyThreshold": 180, + "accountBalance": 25750.45, + "currency": "USD", + "region": "NORTH_AMERICA", + "contactPreference": "email", + "customerEmail": "customer@example.com", + "customerPhone": "+15551234567", + "regulatoryJurisdiction": "US-NY" + }, + "output": { + "actionPriority": "high", + "recommendedAction": "fee_waiver" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 173.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "daysSinceLastActivity", + "value": "date('now') - date(lastActivityDate)" + }, + { + "id": "e1-2", + "key": "daysToThreshold", + "value": "dormancyThreshold - $.daysSinceLastActivity" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculate_dormancy", + "position": { + "x": 430, + "y": 173.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "< 0", + "o1-1": "'dormant'" + }, + { + "_id": "r1-2", + "i1-1": "< 30", + "o1-1": "'at_risk'" + }, + { + "_id": "r1-3", + "i1-1": "< 60", + "o1-1": "'warning'" + }, + { + "_id": "r1-4", + "i1-1": "", + "o1-1": "'active'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Days To Threshold", + "field": "daysToThreshold" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Status", + "field": "dormancyStatus" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "dormancy_status", + "position": { + "x": 750, + "y": 173.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "s1-1", + "condition": "dormancyStatus != 'active'", + "isDefault": false + }, + { + "id": "s1-2", + "condition": "", + "isDefault": true + } + ] + }, + "id": "sw1", + "name": "route_by_status", + "position": { + "x": 1070, + "y": 173.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'dormant'", + "i2-2": "'premium'", + "o2-1": "'fee_waiver'", + "o2-2": "'high'" + }, + { + "_id": "r2-2", + "i2-1": "'dormant'", + "i2-2": "", + "o2-1": "'auto_close'", + "o2-2": "'medium'" + }, + { + "_id": "r2-3", + "i2-1": "'at_risk'", + "i2-2": "'premium'", + "o2-1": "'account_review'", + "o2-2": "'high'" + }, + { + "_id": "r2-4", + "i2-1": "'at_risk'", + "i2-2": "", + "o2-1": "'final_notice'", + "o2-2": "'high'" + }, + { + "_id": "r2-5", + "i2-1": "'warning'", + "i2-2": "", + "o2-1": "'notification'", + "o2-2": "'medium'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Status", + "field": "dormancyStatus" + }, + { + "id": "i2-2", + "name": "Customer Tier", + "field": "customerTier" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Action", + "field": "recommendedAction" + }, + { + "id": "o2-2", + "name": "Priority", + "field": "actionPriority" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "determine_action", + "position": { + "x": 1390, + "y": 173.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ex1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt1", + "targetId": "sw1", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "sw1", + "targetId": "dt2", + "sourceHandle": "s1-1", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/affiliate-commission-calculator.json b/test-data/graphs/affiliate-commission-calculator.json new file mode 100644 index 00000000..2634dfc0 --- /dev/null +++ b/test-data/graphs/affiliate-commission-calculator.json @@ -0,0 +1,228 @@ +{ + "tests": [ + { + "input": { + "productCategory": "fashion", + "monthlyReferrals": 75, + "conversionRate": 0.12, + "isSpecialPromotion": true, + "saleAmount": 350 + }, + "output": { + "commissionAmount": 69.3, + "finalCommissionRate": 0.198, + "promotionMultiplier": 1.25 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 261.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'electronics'", + "o1-1": "0.08", + "o1-2": "0.03" + }, + { + "_id": "r1-2", + "i1-1": "'fashion'", + "o1-1": "0.12", + "o1-2": "0.04" + }, + { + "_id": "r1-3", + "i1-1": "'beauty'", + "o1-1": "0.15", + "o1-2": "0.05" + }, + { + "_id": "r1-4", + "i1-1": "'home_goods'", + "o1-1": "0.10", + "o1-2": "0.03" + }, + { + "_id": "r1-5", + "i1-1": "", + "o1-1": "0.05", + "o1-2": "0.02" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Product Category", + "field": "productCategory" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Base Rate", + "field": "baseCommissionRate" + }, + { + "id": "o1-2", + "name": "Volume Bonus Max", + "field": "volumeBonusMax" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "categoryRates", + "position": { + "x": 430, + "y": 261.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": ">= 100", + "i2-2": ">= 0.15", + "o2-1": "volumeBonusMax", + "o2-2": "1.2" + }, + { + "_id": "r2-2", + "i2-1": ">= 100", + "i2-2": ">= 0.10", + "o2-1": "volumeBonusMax * 0.8", + "o2-2": "1.15" + }, + { + "_id": "r2-3", + "i2-1": ">= 50", + "i2-2": ">= 0.10", + "o2-1": "volumeBonusMax * 0.6", + "o2-2": "1.1" + }, + { + "_id": "r2-4", + "i2-1": ">= 25", + "i2-2": ">= 0.05", + "o2-1": "volumeBonusMax * 0.3", + "o2-2": "1.05" + }, + { + "_id": "r2-5", + "i2-1": "", + "i2-2": "", + "o2-1": "0", + "o2-2": "1" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Monthly Referrals", + "field": "monthlyReferrals" + }, + { + "id": "i2-2", + "name": "Conversion Rate", + "field": "conversionRate" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Volume Bonus", + "field": "volumeBonus" + }, + { + "id": "o2-2", + "name": "Performance Multiplier", + "field": "performanceMultiplier" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "performanceRates", + "position": { + "x": 750, + "y": 261.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "promotionMultiplier", + "value": "isSpecialPromotion ? 1.25 : 1" + }, + { + "id": "e1-2", + "key": "finalCommissionRate", + "value": "(baseCommissionRate + volumeBonus) * performanceMultiplier * $.promotionMultiplier" + }, + { + "id": "e1-3", + "key": "commissionAmount", + "value": "saleAmount * $.finalCommissionRate" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateCommission", + "position": { + "x": 1070, + "y": 261.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt2", + "targetId": "ex1", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/airline-loyalty-points-calculations.json b/test-data/graphs/airline-loyalty-points-calculations.json new file mode 100644 index 00000000..7c8db3e4 --- /dev/null +++ b/test-data/graphs/airline-loyalty-points-calculations.json @@ -0,0 +1,285 @@ +{ + "tests": [ + { + "input": { + "booking": { + "fareClass": "Business", + "routeType": "International", + "distance": 3500, + "isSeasonalPromotion": true + }, + "member": { + "status": "Gold", + "id": "MEM12345", + "name": "John Smith", + "enrollmentDate": "2020-05-15" + } + }, + "output": { + "calculatedPoints": 9000, + "seasonalPromotion": 1.5, + "totalPoints": 9000 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'First'", + "o1-1": "3" + }, + { + "_id": "r1-2", + "i1-1": "'Business'", + "o1-1": "2" + }, + { + "_id": "r1-3", + "i1-1": "'Premium Economy'", + "o1-1": "1.5" + }, + { + "_id": "r1-4", + "i1-1": "'Economy Plus'", + "o1-1": "1.25" + }, + { + "_id": "r1-5", + "i1-1": "", + "o1-1": "1" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Fare Class", + "field": "booking.fareClass" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Fare Multiplier", + "field": "points.fareMultiplier" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "fareClassMultiplier", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'Domestic'", + "i2-2": "< 500", + "o2-1": "250" + }, + { + "_id": "r2-2", + "i2-1": "'Domestic'", + "i2-2": "[500..1000]", + "o2-1": "500" + }, + { + "_id": "r2-3", + "i2-1": "'Domestic'", + "i2-2": "> 1000", + "o2-1": "750" + }, + { + "_id": "r2-4", + "i2-1": "'International'", + "i2-2": "< 2000", + "o2-1": "1000" + }, + { + "_id": "r2-5", + "i2-1": "'International'", + "i2-2": "[2000..5000]", + "o2-1": "2000" + }, + { + "_id": "r2-6", + "i2-1": "'International'", + "i2-2": "> 5000", + "o2-1": "3000" + }, + { + "_id": "r2-7", + "i2-1": "", + "i2-2": "", + "o2-1": "500" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Route Type", + "field": "booking.routeType" + }, + { + "id": "i2-2", + "name": "Distance (miles)", + "field": "booking.distance" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Base Points", + "field": "points.basePoints" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "routeBasePoints", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "'Platinum'", + "o3-1": "2" + }, + { + "_id": "r3-2", + "i3-1": "'Gold'", + "o3-1": "1.5" + }, + { + "_id": "r3-3", + "i3-1": "'Silver'", + "o3-1": "1.25" + }, + { + "_id": "r3-4", + "i3-1": "", + "o3-1": "1" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Member Status", + "field": "member.status" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Status Multiplier", + "field": "points.statusMultiplier" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt3", + "name": "memberStatusMultiplier", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "seasonalPromotion", + "value": "booking.isSeasonalPromotion == true ? 1.5 : 1" + }, + { + "id": "e1-2", + "key": "calculatedPoints", + "value": "floor(points.basePoints * points.fareMultiplier * points.statusMultiplier * $.seasonalPromotion)" + }, + { + "id": "e1-3", + "key": "totalPoints", + "value": "$.calculatedPoints" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateTotalPoints", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt2", + "targetId": "dt3", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "dt3", + "targetId": "ex1", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/airline-upgrade-eligibility.json b/test-data/graphs/airline-upgrade-eligibility.json new file mode 100644 index 00000000..98198b34 --- /dev/null +++ b/test-data/graphs/airline-upgrade-eligibility.json @@ -0,0 +1,466 @@ +{ + "tests": [ + { + "input": { + "passenger": { + "id": "P123456", + "name": "Jane Smith", + "ticketStatus": "confirmed", + "flightStatus": "scheduled", + "checkInStatus": "completed", + "loyaltyStatus": "gold", + "loyaltyMiles": 82500, + "fareClass": "premium economy" + }, + "flight": { + "flightNumber": "FL789", + "departureDate": "2025-04-15", + "route": "LHR-JFK", + "cabinAvailability": 7 + }, + "corporate": { + "agreementLevel": "premier", + "upgradeEligible": true, + "companyName": "Acme Corporation" + } + }, + "output": { + "result": { + "isEligible": false, + "reason": "Check-in not completed", + "score": 0 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1-1": "!= 'confirmed'", + "o1-1": "false", + "o1-2": "'Ticket not confirmed'" + }, + { + "_id": "rule2", + "i1-1": "'cancelled'", + "o1-1": "false", + "o1-2": "'Flight cancelled'" + }, + { + "_id": "rule3", + "i1-1": "!= 'completed'", + "o1-1": "false", + "o1-2": "'Check-in not completed'" + }, + { + "_id": "rule4", + "i1-1": "", + "o1-1": "true", + "o1-2": "'Basic eligibility confirmed'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Ticket status", + "field": "passenger.ticketStatus" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "IsEligible", + "field": "basicEligibility.isEligible" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "basicEligibility.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "checkBasicEligibility", + "name": "checkBasicEligibility", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i2-1": "'platinum'", + "i2-2": "> 100000", + "o2-1": "50" + }, + { + "_id": "rule2", + "i2-1": "'platinum'", + "i2-2": "", + "o2-1": "40" + }, + { + "_id": "rule3", + "i2-1": "'gold'", + "i2-2": "> 75000", + "o2-1": "35" + }, + { + "_id": "rule4", + "i2-1": "'gold'", + "i2-2": "", + "o2-1": "30" + }, + { + "_id": "rule5", + "i2-1": "'silver'", + "i2-2": "> 50000", + "o2-1": "25" + }, + { + "_id": "rule6", + "i2-1": "'silver'", + "i2-2": "", + "o2-1": "20" + }, + { + "_id": "rule7", + "i2-1": "'member'", + "i2-2": "> 25000", + "o2-1": "15" + }, + { + "_id": "rule8", + "i2-1": "'member'", + "i2-2": "", + "o2-1": "10" + }, + { + "_id": "rule9", + "i2-1": "", + "i2-2": "", + "o2-1": "0" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Status", + "field": "passenger.loyaltyStatus" + }, + { + "id": "i2-2", + "name": "Miles", + "field": "passenger.loyaltyMiles" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Score", + "field": "scores.loyalty" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "calculateLoyaltyScore", + "name": "calculateLoyaltyScore", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i3-1": "'business'", + "o3-1": "30" + }, + { + "_id": "rule2", + "i3-1": "'premium economy'", + "o3-1": "20" + }, + { + "_id": "rule3", + "i3-1": "'economy flex'", + "o3-1": "15" + }, + { + "_id": "rule4", + "i3-1": "'economy standard'", + "o3-1": "10" + }, + { + "_id": "rule5", + "i3-1": "'economy basic'", + "o3-1": "5" + }, + { + "_id": "rule6", + "i3-1": "", + "o3-1": "0" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "FareClass", + "field": "passenger.fareClass" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Score", + "field": "scores.fare" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "calculateFareScore", + "name": "calculateFareScore", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i4-1": "'premier'", + "i4-2": "true", + "o4-1": "25" + }, + { + "_id": "rule2", + "i4-1": "'standard'", + "i4-2": "true", + "o4-1": "15" + }, + { + "_id": "rule3", + "i4-1": "!= null", + "i4-2": "", + "o4-1": "5" + }, + { + "_id": "rule4", + "i4-1": "", + "i4-2": "", + "o4-1": "0" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "Agreement Level", + "field": "corporate.agreementLevel" + }, + { + "id": "i4-2", + "name": "Eligible", + "field": "corporate.upgradeEligible" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "Score", + "field": "scores.corporate" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "checkCorporateAgreement", + "name": "checkCorporateAgreement", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "totalScore", + "value": "scores.loyalty + scores.fare + scores.corporate" + }, + { + "id": "expr2", + "key": "cabinMultiplier", + "value": "flight.cabinAvailability > 10 ? 1.2 : flight.cabinAvailability > 5 ? 1.0 : flight.cabinAvailability > 2 ? 0.8 : 0.5" + }, + { + "id": "expr3", + "key": "finalScore", + "value": "$.totalScore * $.cabinMultiplier" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "evaluateCabinAvailability", + "name": "evaluateCabinAvailability", + "position": { + "x": 1710, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i5-1": "basicEligibility.isEligible == false", + "o5-1": "false", + "o5-2": "basicEligibility.reason", + "o5-3": "0" + }, + { + "_id": "rule2", + "i5-1": "finalScore >= 75", + "o5-1": "true", + "o5-2": "'Premium upgrade approved'", + "o5-3": "finalScore" + }, + { + "_id": "rule3", + "i5-1": "finalScore >= 50", + "o5-1": "true", + "o5-2": "'Standard upgrade approved'", + "o5-3": "finalScore" + }, + { + "_id": "rule4", + "i5-1": "", + "o5-1": "false", + "o5-2": "'Insufficient score for upgrade'", + "o5-3": "finalScore" + } + ], + "inputs": [ + { + "id": "i5-1", + "name": "Condition" + } + ], + "outputs": [ + { + "id": "o5-1", + "name": "Eligible", + "field": "result.isEligible" + }, + { + "id": "o5-2", + "name": "Reason", + "field": "result.reason" + }, + { + "id": "o5-3", + "name": "Score", + "field": "result.score" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "determineUpgradeEligibility", + "name": "determineUpgradeEligibility", + "position": { + "x": 2030, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "checkBasicEligibility", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "checkBasicEligibility", + "targetId": "calculateLoyaltyScore", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "calculateLoyaltyScore", + "targetId": "calculateFareScore", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "calculateFareScore", + "targetId": "checkCorporateAgreement", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "checkCorporateAgreement", + "targetId": "evaluateCabinAvailability", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "evaluateCabinAvailability", + "targetId": "determineUpgradeEligibility", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/application-risk-assessment.json b/test-data/graphs/application-risk-assessment.json new file mode 100644 index 00000000..242ed2a6 --- /dev/null +++ b/test-data/graphs/application-risk-assessment.json @@ -0,0 +1,474 @@ +{ + "tests": [ + { + "input": { + "applicant": { + "creditScore": 710, + "latePayments": 1, + "creditHistoryMonths": 48, + "employmentMonths": 36, + "incomeVerification": "complete", + "bankAccountStanding": "good", + "debtToIncomeRatio": 0.35, + "outstandingLoans": 2 + } + }, + "output": { + "applicant": { + "bankAccountStanding": "good", + "creditHistoryMonths": 48, + "creditScore": 710, + "debtToIncomeRatio": 0.35, + "employmentMonths": 36, + "incomeVerification": "complete", + "latePayments": 1, + "outstandingLoans": 2 + }, + "approvalStatus": "manual-review", + "interestRateModifier": 0, + "negativeFactors": [], + "negativeFactorsCount": 0, + "riskCategory": "medium", + "scores": { + "creditHistory": 20, + "debtToIncome": 15, + "incomeStability": 20 + }, + "totalRiskScore": 55 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 163.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "> 750", + "i1-2": "< 2", + "i1-3": "> 60", + "o1-1": "30" + }, + { + "_id": "r1-2", + "i1-1": "[650..750]", + "i1-2": "< 4", + "i1-3": "> 36", + "o1-1": "20" + }, + { + "_id": "r1-3", + "i1-1": "[600..650)", + "i1-2": "< 6", + "i1-3": "> 24", + "o1-1": "10" + }, + { + "_id": "r1-4", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "o1-1": "0" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "creditScore", + "field": "applicant.creditScore" + }, + { + "id": "i1-2", + "name": "latePayments", + "field": "applicant.latePayments" + }, + { + "id": "i1-3", + "name": "creditHistoryLength", + "field": "applicant.creditHistoryMonths" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "creditHistoryScore", + "field": "scores.creditHistory" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "scoreCreditHistory", + "name": "scoreCreditHistory", + "position": { + "x": 430, + "y": 163.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "> 60", + "i2-2": "'complete'", + "i2-3": "'good'", + "o2-1": "25" + }, + { + "_id": "r2-2", + "i2-1": "> 24", + "i2-2": "'complete'", + "i2-3": "'good'", + "o2-1": "20" + }, + { + "_id": "r2-3", + "i2-1": "> 12", + "i2-2": "'partial'", + "i2-3": "'fair'", + "o2-1": "15" + }, + { + "_id": "r2-4", + "i2-1": "> 6", + "i2-2": "", + "i2-3": "", + "o2-1": "5" + }, + { + "_id": "r2-5", + "i2-1": "", + "i2-2": "", + "i2-3": "", + "o2-1": "0" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "employmentLength", + "field": "applicant.employmentMonths" + }, + { + "id": "i2-2", + "name": "incomeVerification", + "field": "applicant.incomeVerification" + }, + { + "id": "i2-3", + "name": "bankAccountStanding", + "field": "applicant.bankAccountStanding" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "incomeStabilityScore", + "field": "scores.incomeStability" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "scoreIncomeStability", + "name": "scoreIncomeStability", + "position": { + "x": 750, + "y": 163.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "< 0.2", + "i3-2": "< 2", + "o3-1": "25" + }, + { + "_id": "r3-2", + "i3-1": "< 0.4", + "i3-2": "< 3", + "o3-1": "15" + }, + { + "_id": "r3-3", + "i3-1": "< 0.6", + "i3-2": "< 5", + "o3-1": "5" + }, + { + "_id": "r3-4", + "i3-1": "", + "i3-2": "", + "o3-1": "0" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "debtToIncomeRatio", + "field": "applicant.debtToIncomeRatio" + }, + { + "id": "i3-2", + "name": "outstandingLoans", + "field": "applicant.outstandingLoans" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "debtToIncomeScore", + "field": "scores.debtToIncome" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "scoreDebtToIncome", + "name": "scoreDebtToIncome", + "position": { + "x": 1070, + "y": 163.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e4-1", + "key": "totalRiskScore", + "value": "scores.creditHistory + scores.incomeStability + scores.debtToIncome" + }, + { + "id": "e4-2", + "key": "negativeFactors", + "value": "filter([scores.creditHistory == 0, scores.incomeStability == 0, scores.debtToIncome == 0], # == true)" + }, + { + "id": "e4-3", + "key": "negativeFactorsCount", + "value": "len($.negativeFactors)" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "calculateRiskScore", + "name": "calculateRiskScore", + "position": { + "x": 1390, + "y": 163.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "s1", + "condition": "totalRiskScore >= 60 and negativeFactorsCount == 0", + "isDefault": false + }, + { + "id": "s2", + "condition": "totalRiskScore >= 30 or (totalRiskScore >= 20 and negativeFactorsCount < 2)", + "isDefault": false + }, + { + "id": "s3", + "condition": "", + "isDefault": true + } + ] + }, + "id": "classifyRisk", + "name": "classifyRisk", + "position": { + "x": 1710, + "y": 163.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e6-1", + "key": "riskCategory", + "value": "'low'" + }, + { + "id": "e6-2", + "key": "approvalStatus", + "value": "'auto-approved'" + }, + { + "id": "e6-3", + "key": "interestRateModifier", + "value": "-0.5" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "lowRiskAction", + "name": "lowRiskAction", + "position": { + "x": 2030, + "y": 65.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e7-1", + "key": "riskCategory", + "value": "'medium'" + }, + { + "id": "e7-2", + "key": "approvalStatus", + "value": "'manual-review'" + }, + { + "id": "e7-3", + "key": "interestRateModifier", + "value": "0" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "mediumRiskAction", + "name": "mediumRiskAction", + "position": { + "x": 2030, + "y": 163.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e8-1", + "key": "riskCategory", + "value": "'high'" + }, + { + "id": "e8-2", + "key": "approvalStatus", + "value": "'additional-verification'" + }, + { + "id": "e8-3", + "key": "interestRateModifier", + "value": "1.5" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "highRiskAction", + "name": "highRiskAction", + "position": { + "x": 2030, + "y": 261.5 + } + } + ], + "edges": [ + { + "id": "e1", + "sourceId": "input", + "targetId": "scoreCreditHistory", + "type": "edge" + }, + { + "id": "e2", + "sourceId": "scoreCreditHistory", + "targetId": "scoreIncomeStability", + "type": "edge" + }, + { + "id": "e3", + "sourceId": "scoreIncomeStability", + "targetId": "scoreDebtToIncome", + "type": "edge" + }, + { + "id": "e4", + "sourceId": "scoreDebtToIncome", + "targetId": "calculateRiskScore", + "type": "edge" + }, + { + "id": "e5", + "sourceId": "calculateRiskScore", + "targetId": "classifyRisk", + "type": "edge" + }, + { + "id": "e6", + "sourceId": "classifyRisk", + "targetId": "lowRiskAction", + "sourceHandle": "s1", + "type": "edge" + }, + { + "id": "e7", + "sourceId": "classifyRisk", + "targetId": "mediumRiskAction", + "sourceHandle": "s2", + "type": "edge" + }, + { + "id": "e8", + "sourceId": "classifyRisk", + "targetId": "highRiskAction", + "sourceHandle": "s3", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/auto-insurance-premium-calculator.json b/test-data/graphs/auto-insurance-premium-calculator.json new file mode 100644 index 00000000..ea7caada --- /dev/null +++ b/test-data/graphs/auto-insurance-premium-calculator.json @@ -0,0 +1,412 @@ +{ + "tests": [ + { + "input": { + "customer": { + "age": 35, + "gender": "female", + "creditScore": 720, + "drivingHistory": { + "accidentsLast3Years": 0, + "violationsLast3Years": 1 + } + }, + "policy": { + "coverageAmount": 300000, + "coverageType": "comprehensive", + "deductible": 500, + "vehicleAge": 3, + "vehicleType": "sedan" + } + }, + "output": { + "basePremium": 1650, + "basePremiumPerThousand": 5.5, + "coverageAmountInThousands": 300, + "customer": { + "age": 35, + "creditScore": 720, + "drivingHistory": { + "accidentsLast3Years": 0, + "violationsLast3Years": 1 + }, + "gender": "female" + }, + "policy": { + "coverageAmount": 300000, + "coverageType": "comprehensive", + "deductible": 500, + "vehicleAge": 3, + "vehicleType": "sedan" + }, + "riskFactors": { + "ageRiskFactor": 1.2, + "driverRiskCategory": "medium", + "vehicleRiskFactor": 1 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "< 25", + "i1-2": "> 1", + "o1-1": "1.5", + "o1-2": "'high'" + }, + { + "_id": "r1-2", + "i1-1": "< 25", + "i1-2": "0, 1", + "o1-1": "1.3", + "o1-2": "'medium-high'" + }, + { + "_id": "r1-3", + "i1-1": "[25..65]", + "i1-2": "> 2", + "o1-1": "1.4", + "o1-2": "'medium-high'" + }, + { + "_id": "r1-4", + "i1-1": "[25..65]", + "i1-2": "1, 2", + "o1-1": "1.2", + "o1-2": "'medium'" + }, + { + "_id": "r1-5", + "i1-1": "[25..65]", + "i1-2": "0", + "o1-1": "1.0", + "o1-2": "'low'" + }, + { + "_id": "r1-6", + "i1-1": "> 65", + "i1-2": "> 0", + "o1-1": "1.3", + "o1-2": "'medium-high'" + }, + { + "_id": "r1-7", + "i1-1": "> 65", + "i1-2": "0", + "o1-1": "1.1", + "o1-2": "'medium-low'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Age", + "field": "customer.age" + }, + { + "id": "i1-2", + "name": "Total Incidents", + "field": "customer.drivingHistory.accidentsLast3Years + customer.drivingHistory.violationsLast3Years" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Age Risk Factor", + "field": "riskFactors.ageRiskFactor" + }, + { + "id": "o1-2", + "name": "Driver Risk Category", + "field": "riskFactors.driverRiskCategory" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "driverRiskAssessment", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "basePremiumPerThousand", + "value": "5.5" + }, + { + "id": "e1-2", + "key": "coverageAmountInThousands", + "value": "policy.coverageAmount / 1000" + }, + { + "id": "e1-3", + "key": "basePremium", + "value": "$.basePremiumPerThousand * $.coverageAmountInThousands" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateBasePremium", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'sedan'", + "i2-2": "< 3", + "o2-1": "0.9" + }, + { + "_id": "r2-2", + "i2-1": "'sedan'", + "i2-2": "[3..7]", + "o2-1": "1.0" + }, + { + "_id": "r2-3", + "i2-1": "'sedan'", + "i2-2": "> 7", + "o2-1": "1.1" + }, + { + "_id": "r2-4", + "i2-1": "'suv'", + "i2-2": "< 3", + "o2-1": "1.1" + }, + { + "_id": "r2-5", + "i2-1": "'suv'", + "i2-2": "[3..7]", + "o2-1": "1.2" + }, + { + "_id": "r2-6", + "i2-1": "'suv'", + "i2-2": "> 7", + "o2-1": "1.3" + }, + { + "_id": "r2-7", + "i2-1": "'sports'", + "i2-2": "< 3", + "o2-1": "1.5" + }, + { + "_id": "r2-8", + "i2-1": "'sports'", + "i2-2": "[3..7]", + "o2-1": "1.6" + }, + { + "_id": "r2-9", + "i2-1": "'sports'", + "i2-2": "> 7", + "o2-1": "1.8" + }, + { + "_id": "r2-10", + "i2-1": "", + "i2-2": "", + "o2-1": "1.2" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Vehicle Type", + "field": "policy.vehicleType" + }, + { + "id": "i2-2", + "name": "Vehicle Age", + "field": "policy.vehicleAge" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Vehicle Risk Factor", + "field": "riskFactors.vehicleRiskFactor" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "vehicleRiskAssessment", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "'basic'", + "i3-2": "> 1000", + "o3-1": "0.8" + }, + { + "_id": "r3-2", + "i3-1": "'basic'", + "i3-2": "[500..1000]", + "o3-1": "0.9" + }, + { + "_id": "r3-3", + "i3-1": "'basic'", + "i3-2": "< 500", + "o3-1": "1.0" + }, + { + "_id": "r3-4", + "i3-1": "'standard'", + "i3-2": "> 1000", + "o3-1": "0.9" + }, + { + "_id": "r3-5", + "i3-1": "'standard'", + "i3-2": "[500..1000]", + "o3-1": "1.0" + }, + { + "_id": "r3-6", + "i3-1": "'standard'", + "i3-2": "< 500", + "o3-1": "1.1" + }, + { + "_id": "r3-7", + "i3-1": "'comprehensive'", + "i3-2": "> 1000", + "o3-1": "1.1" + }, + { + "_id": "r3-8", + "i3-1": "'comprehensive'", + "i3-2": "[500..1000]", + "o3-1": "1.2" + }, + { + "_id": "r3-9", + "i3-1": "'comprehensive'", + "i3-2": "< 500", + "o3-1": "1.3" + }, + { + "_id": "r3-10", + "i3-1": "", + "i3-2": "", + "o3-1": "1.0" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Coverage Type", + "field": "policy.coverageType" + }, + { + "id": "i3-2", + "name": "Deductible", + "field": "policy.deductible" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Coverage Factor", + "field": "riskFactors.coverageFactor" + }, + { + "id": "o3-2", + "name": "Final Premium", + "field": "premium" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt3", + "name": "finalPremiumCalculation", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ex1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "dt2", + "targetId": "dt3", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/booking-fraud-detection.json b/test-data/graphs/booking-fraud-detection.json new file mode 100644 index 00000000..b96072f7 --- /dev/null +++ b/test-data/graphs/booking-fraud-detection.json @@ -0,0 +1,428 @@ +{ + "tests": [ + { + "input": { + "booking": { + "payment_method": "prepaid_card", + "amount": 2500, + "ip_country": "US" + }, + "account": { + "country": "US", + "bookings_last_24h": 6 + } + }, + "output": { + "flags": { + "manual_review": true, + "requires_verification": true + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'prepaid_card'", + "i1-2": "> 2000", + "o1-1": "40", + "o1-2": "'High-value prepaid card transaction'" + }, + { + "_id": "r1-2", + "i1-1": "'prepaid_card'", + "i1-2": "", + "o1-1": "20", + "o1-2": "'Prepaid card transaction'" + }, + { + "_id": "r1-3", + "i1-1": "'gift_card'", + "i1-2": "> 1000", + "o1-1": "30", + "o1-2": "'High-value gift card transaction'" + }, + { + "_id": "r1-4", + "i1-1": "'gift_card'", + "i1-2": "", + "o1-1": "15", + "o1-2": "'Gift card transaction'" + }, + { + "_id": "r1-5", + "i1-1": "'cryptocurrency'", + "i1-2": "", + "o1-1": "25", + "o1-2": "'Cryptocurrency transaction'" + }, + { + "_id": "r1-6", + "i1-1": "'credit_card'", + "i1-2": "> 3000", + "o1-1": "15", + "o1-2": "'High-value credit card transaction'" + }, + { + "_id": "r1-7", + "i1-1": "", + "i1-2": "", + "o1-1": "0", + "o1-2": "'Standard transaction'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Payment Method", + "field": "booking.payment_method" + }, + { + "id": "i1-2", + "name": "Transaction Amount", + "field": "booking.amount" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Payment Risk Score", + "field": "risk.payment.score" + }, + { + "id": "o1-2", + "name": "Payment Risk Reason", + "field": "risk.payment.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt1", + "name": "payment_risk", + "position": { + "x": 430, + "y": 16 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "> 5", + "i2-2": "!= booking.ip_country", + "o2-1": "50", + "o2-2": "'Multiple bookings from different country'" + }, + { + "_id": "r2-2", + "i2-1": "> 5", + "i2-2": "", + "o2-1": "30", + "o2-2": "'Multiple rapid bookings'" + }, + { + "_id": "r2-3", + "i2-1": "> 3", + "i2-2": "!= booking.ip_country", + "o2-1": "35", + "o2-2": "'Several bookings from different country'" + }, + { + "_id": "r2-4", + "i2-1": "> 3", + "i2-2": "", + "o2-1": "20", + "o2-2": "'Several rapid bookings'" + }, + { + "_id": "r2-5", + "i2-1": "", + "i2-2": "!= booking.ip_country", + "o2-1": "25", + "o2-2": "'Booking from different country'" + }, + { + "_id": "r2-6", + "i2-1": "", + "i2-2": "", + "o2-1": "0", + "o2-2": "'Normal booking pattern'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Recent Bookings 24h", + "field": "account.bookings_last_24h" + }, + { + "id": "i2-2", + "name": "Account Country", + "field": "account.country" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Pattern Risk Score", + "field": "risk.pattern.score" + }, + { + "id": "o2-2", + "name": "Pattern Risk Reason", + "field": "risk.pattern.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt2", + "name": "pattern_risk", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "< 30", + "o3-1": "40", + "o3-2": "'New account with significant transaction'" + }, + { + "_id": "r3-2", + "i3-1": "< 90", + "o3-1": "20", + "o3-2": "'Relatively new account'" + }, + { + "_id": "r3-3", + "i3-1": "> 1", + "o3-1": "15", + "o3-2": "'Previous chargeback history'" + }, + { + "_id": "r3-4", + "i3-1": "", + "o3-1": "0", + "o3-2": "'Normal account history'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Account Age (days)", + "field": "account.age_days" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Account Risk Score", + "field": "risk.account.score" + }, + { + "id": "o3-2", + "name": "Account Risk Reason", + "field": "risk.account.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt3", + "name": "account_risk", + "position": { + "x": 430, + "y": 212 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "total_risk_score", + "value": "sum(\n map(values(risk), #.score)\n)" + }, + { + "id": "e1-5", + "key": "risk_factors", + "value": "map(\n filter(values(risk), #.score > 0),\n #.reason\n)" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "risk_calculation", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "42dc5a6d-6605-40b6-83b4-bad0bcf445c6", + "7385e66d-dc97-4048-a214-3f35d0029465": ">= 70", + "35a4cafc-e27c-4419-bfd3-b89a3dcddf46": "\"high\"" + }, + { + "_id": "c7910082-59fa-4aaf-b67e-5f807db68180", + "7385e66d-dc97-4048-a214-3f35d0029465": ">= 30", + "35a4cafc-e27c-4419-bfd3-b89a3dcddf46": "\"medium\"" + }, + { + "_id": "cea70345-a575-4c72-a81d-b2808f1193ff", + "7385e66d-dc97-4048-a214-3f35d0029465": "", + "35a4cafc-e27c-4419-bfd3-b89a3dcddf46": "\"low\"" + } + ], + "inputs": [ + { + "id": "7385e66d-dc97-4048-a214-3f35d0029465", + "name": "Total risk score", + "field": "total_risk_score" + } + ], + "outputs": [ + { + "id": "35a4cafc-e27c-4419-bfd3-b89a3dcddf46", + "name": "Risk level", + "field": "risk_level" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "9213dd68-a9f4-4b90-ada9-c7418d8b3c51", + "name": "risk_level", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "d58ad60e-a542-4213-919d-66db853847ef", + "key": "flags.requires_verification", + "value": "risk_level in [\"medium\", \"high\"]" + }, + { + "id": "898fd37d-5370-4e9b-afa7-e04628805b29", + "key": "flags.manual_review", + "value": "risk_level == \"high\"" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "e6dd7428-9ce6-4d8d-9a62-e38af18da14b", + "name": "flags", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ip1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ip1", + "targetId": "dt3", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed5", + "sourceId": "dt2", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed6", + "sourceId": "dt3", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "018917a8-1af8-4de1-88e9-f7aa829006fc", + "sourceId": "ex1", + "type": "edge", + "targetId": "9213dd68-a9f4-4b90-ada9-c7418d8b3c51" + }, + { + "id": "c627b3e0-ed4f-4701-a10c-668c84a96e70", + "sourceId": "9213dd68-a9f4-4b90-ada9-c7418d8b3c51", + "type": "edge", + "targetId": "e6dd7428-9ce6-4d8d-9a62-e38af18da14b" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/booking-personalization-system.json b/test-data/graphs/booking-personalization-system.json new file mode 100644 index 00000000..14decedb --- /dev/null +++ b/test-data/graphs/booking-personalization-system.json @@ -0,0 +1,553 @@ +{ + "tests": [ + { + "input": { + "flightId": "FL-123", + "routeId": "JFK-LAX", + "daysToDepature": 5, + "basePrice": 250, + "availableSeats": 35, + "totalSeats": 180, + "demandForecast": 75, + "avgCompetitorPrice": 275 + }, + "output": { + "allFeatures": [ + "standardSearch", + "standardNavigation", + "joinLoyaltyBanner", + "standardOptions" + ], + "bookingFlowTemplate": "basic", + "totalDiscountPercentage": 0 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "dt-rule1", + "deviceType": "'mobile'", + "uiElements": "['compactSearch', 'simplifiedNavigation', 'touchFriendlyControls']", + "layoutConfig": "{ 'type': 'compact', 'imageSize': 'small', 'showExtras': false }" + }, + { + "_id": "dt-rule2", + "deviceType": "'tablet'", + "uiElements": "['touchFriendlyControls', 'mediumSearch', 'fullNavigation']", + "layoutConfig": "{ 'type': 'medium', 'imageSize': 'medium', 'showExtras': true }" + }, + { + "_id": "dt-rule3", + "deviceType": "'desktop'", + "uiElements": "['expandedSearch', 'fullNavigation', 'detailedFilters']", + "layoutConfig": "{ 'type': 'full', 'imageSize': 'large', 'showExtras': true }" + }, + { + "_id": "dt-rule4", + "deviceType": "", + "uiElements": "['standardSearch', 'standardNavigation']", + "layoutConfig": "{ 'type': 'standard', 'imageSize': 'medium', 'showExtras': true }" + } + ], + "inputs": [ + { + "id": "deviceType", + "name": "Device Type", + "field": "customer.deviceType" + } + ], + "outputs": [ + { + "id": "uiElements", + "name": "UI Elements", + "field": "personalization.uiElements" + }, + { + "id": "layoutConfig", + "name": "Layout Configuration", + "field": "personalization.layoutConfig" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "deviceTypeTable", + "name": "Device Type Personalization", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "ls-rule1", + "loyaltyStatus": "'platinum'", + "priority": "1", + "showFeatures": "['priorityBooking', 'exclusiveDeals', 'conciergeService', 'upgradeOffers']", + "discountPercentage": "15" + }, + { + "_id": "ls-rule2", + "loyaltyStatus": "'gold'", + "priority": "2", + "showFeatures": "['priorityBooking', 'memberDeals', 'upgradeOffers']", + "discountPercentage": "10" + }, + { + "_id": "ls-rule3", + "loyaltyStatus": "'silver'", + "priority": "3", + "showFeatures": "['memberDeals', 'basicUpgrades']", + "discountPercentage": "5" + }, + { + "_id": "ls-rule4", + "loyaltyStatus": "'none'", + "priority": "4", + "showFeatures": "['joinLoyaltyBanner', 'standardOptions']", + "discountPercentage": "0" + }, + { + "_id": "ls-rule5", + "loyaltyStatus": "", + "priority": "4", + "showFeatures": "['joinLoyaltyBanner', 'standardOptions']", + "discountPercentage": "0" + } + ], + "inputs": [ + { + "id": "loyaltyStatus", + "name": "Loyalty Status", + "field": "customer.loyaltyStatus" + } + ], + "outputs": [ + { + "id": "priority", + "name": "Customer Priority", + "field": "personalization.customerPriority" + }, + { + "id": "showFeatures", + "name": "Features to Show", + "field": "personalization.loyaltyFeatures" + }, + { + "id": "discountPercentage", + "name": "Discount Percentage", + "field": "personalization.baseDiscountPercentage" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "loyaltyStatusTable", + "name": "Loyalty Status Personalization", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "vs-rule1", + "visitSource": "'email_campaign'", + "showSpecialOffers": "true", + "specialOffersType": "'emailPromotions'", + "addDiscount": "2" + }, + { + "_id": "vs-rule2", + "visitSource": "'search_engine'", + "showSpecialOffers": "true", + "specialOffersType": "'searchSpecials'", + "addDiscount": "0" + }, + { + "_id": "vs-rule3", + "visitSource": "'social_media'", + "showSpecialOffers": "true", + "specialOffersType": "'socialMediaDeals'", + "addDiscount": "3" + }, + { + "_id": "vs-rule4", + "visitSource": "'partner_site'", + "showSpecialOffers": "true", + "specialOffersType": "'partnerOffers'", + "addDiscount": "5" + }, + { + "_id": "vs-rule5", + "visitSource": "'direct'", + "showSpecialOffers": "false", + "specialOffersType": "'none'", + "addDiscount": "0" + }, + { + "_id": "vs-rule6", + "visitSource": "", + "showSpecialOffers": "false", + "specialOffersType": "'standardOffers'", + "addDiscount": "0" + } + ], + "inputs": [ + { + "id": "visitSource", + "name": "Visit Source", + "field": "customer.visitSource" + } + ], + "outputs": [ + { + "id": "showSpecialOffers", + "name": "Show Special Offers", + "field": "personalization.showSpecialOffers" + }, + { + "id": "specialOffersType", + "name": "Special Offers Type", + "field": "personalization.specialOffersType" + }, + { + "id": "addDiscount", + "name": "Additional Discount", + "field": "personalization.additionalDiscountPercentage" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "visitSourceTable", + "name": "Visit Source Personalization", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "bh-rule1", + "totalBookings": "> 10", + "recentBookings": "> 2", + "recommendationType": "'frequentTraveler'", + "showRecentlyViewed": "true", + "addDiscount": "3" + }, + { + "_id": "bh-rule2", + "totalBookings": "> 5", + "recentBookings": "> 1", + "recommendationType": "'regularCustomer'", + "showRecentlyViewed": "true", + "addDiscount": "2" + }, + { + "_id": "bh-rule3", + "totalBookings": "> 0", + "recentBookings": "== 0", + "recommendationType": "'returningCustomer'", + "showRecentlyViewed": "false", + "addDiscount": "1" + }, + { + "_id": "bh-rule4", + "totalBookings": "== 0", + "recentBookings": "== 0", + "recommendationType": "'newCustomer'", + "showRecentlyViewed": "false", + "addDiscount": "0" + }, + { + "_id": "bh-rule5", + "totalBookings": "", + "recentBookings": "", + "recommendationType": "'standard'", + "showRecentlyViewed": "false", + "addDiscount": "0" + } + ], + "inputs": [ + { + "id": "totalBookings", + "name": "Total Bookings", + "field": "customer.bookingHistory.totalBookings" + }, + { + "id": "recentBookings", + "name": "Recent Bookings (Last 90 Days)", + "field": "customer.bookingHistory.recentBookings" + } + ], + "outputs": [ + { + "id": "recommendationType", + "name": "Recommendation Type", + "field": "personalization.recommendationType" + }, + { + "id": "showRecentlyViewed", + "name": "Show Recently Viewed", + "field": "personalization.showRecentlyViewed" + }, + { + "id": "addDiscount", + "name": "History Discount", + "field": "personalization.historyDiscountPercentage" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "bookingHistoryTable", + "name": "Booking History Personalization", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "ps-rule1", + "totalBookingsCheck": "> 0", + "loyaltyPriority": "1", + "visitSourceCheck": "'social_media', 'partner_site'", + "personalizationScore": "65" + }, + { + "_id": "ps-rule2", + "totalBookingsCheck": "> 0", + "loyaltyPriority": "1", + "visitSourceCheck": "", + "personalizationScore": "50" + }, + { + "_id": "ps-rule3", + "totalBookingsCheck": "> 0", + "loyaltyPriority": "2", + "visitSourceCheck": "'social_media', 'partner_site'", + "personalizationScore": "55" + }, + { + "_id": "ps-rule4", + "totalBookingsCheck": "> 0", + "loyaltyPriority": "2", + "visitSourceCheck": "", + "personalizationScore": "40" + }, + { + "_id": "ps-rule5", + "totalBookingsCheck": "> 0", + "loyaltyPriority": "3", + "visitSourceCheck": "'social_media', 'partner_site'", + "personalizationScore": "45" + }, + { + "_id": "ps-rule6", + "totalBookingsCheck": "> 0", + "loyaltyPriority": "3", + "visitSourceCheck": "", + "personalizationScore": "30" + }, + { + "_id": "ps-rule7", + "totalBookingsCheck": "> 0", + "loyaltyPriority": "", + "visitSourceCheck": "'social_media', 'partner_site'", + "personalizationScore": "35" + }, + { + "_id": "ps-rule8", + "totalBookingsCheck": "> 0", + "loyaltyPriority": "", + "visitSourceCheck": "", + "personalizationScore": "20" + }, + { + "_id": "ps-rule9", + "totalBookingsCheck": "0", + "loyaltyPriority": "1", + "visitSourceCheck": "", + "personalizationScore": "30" + }, + { + "_id": "ps-rule10", + "totalBookingsCheck": "0", + "loyaltyPriority": "2", + "visitSourceCheck": "", + "personalizationScore": "20" + }, + { + "_id": "ps-rule11", + "totalBookingsCheck": "0", + "loyaltyPriority": "3", + "visitSourceCheck": "", + "personalizationScore": "10" + }, + { + "_id": "ps-rule12", + "totalBookingsCheck": "0", + "loyaltyPriority": "", + "visitSourceCheck": "'social_media', 'partner_site'", + "personalizationScore": "15" + }, + { + "_id": "ps-rule13", + "totalBookingsCheck": "", + "loyaltyPriority": "", + "visitSourceCheck": "", + "personalizationScore": "5" + } + ], + "inputs": [ + { + "id": "totalBookingsCheck", + "name": "Has Previous Bookings", + "field": "customer.bookingHistory.totalBookings" + }, + { + "id": "loyaltyPriority", + "name": "Loyalty Priority", + "field": "personalization.customerPriority" + }, + { + "id": "visitSourceCheck", + "name": "Visit Source", + "field": "customer.visitSource" + } + ], + "outputs": [ + { + "id": "personalizationScore", + "name": "Personalization Score", + "field": "personalization.personalizationScore" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "personalizationScoreTable", + "name": "Calculate Personalization Score", + "position": { + "x": 1710, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "totalDiscountPercentage", + "value": "number(personalization.baseDiscountPercentage) + number(personalization.additionalDiscountPercentage) + number(personalization.historyDiscountPercentage)" + }, + { + "id": "expr2", + "key": "bookingFlowTemplate", + "value": "personalization.personalizationScore > 50 ? 'premium' : personalization.personalizationScore > 30 ? 'enhanced' : personalization.personalizationScore > 10 ? 'standard' : 'basic'" + }, + { + "id": "expr3", + "key": "allFeatures", + "value": "flatten([personalization.uiElements, personalization.loyaltyFeatures])" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "finalPersonalization", + "name": "Calculate Final Personalization", + "position": { + "x": 2030, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "deviceTypeTable", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "deviceTypeTable", + "targetId": "loyaltyStatusTable", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "loyaltyStatusTable", + "targetId": "visitSourceTable", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "visitSourceTable", + "targetId": "bookingHistoryTable", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "bookingHistoryTable", + "targetId": "personalizationScoreTable", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "personalizationScoreTable", + "targetId": "finalPersonalization", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/care-team-assignment-system.json b/test-data/graphs/care-team-assignment-system.json new file mode 100644 index 00000000..bcb65fc6 --- /dev/null +++ b/test-data/graphs/care-team-assignment-system.json @@ -0,0 +1,585 @@ +{ + "tests": [ + { + "input": { + "patient": { + "id": "PT12345", + "name": "John Smith", + "age": 67, + "gender": "male", + "careComplexity": "high", + "mobilityScore": 35, + "conditions": [ + "diabetes", + "heart_disease", + "hypertension", + "depression" + ], + "primaryLanguage": "english", + "insuranceType": "medicare", + "carePreferences": { + "preferredGender": "any", + "preferredLanguage": "english", + "requiresTranslator": false + } + }, + "facility": { + "id": "FAC789", + "name": "Memorial Medical Center", + "department": "Internal Medicine" + }, + "availableProviders": [ + { + "id": "DR001", + "name": "Dr. Sarah Johnson", + "role": "primary_physician", + "specialties": [ + "internal_medicine", + "geriatrics" + ], + "languages": [ + "english", + "spanish" + ] + }, + { + "id": "DR002", + "name": "Dr. Michael Chen", + "role": "cardiologist", + "specialties": [ + "cardiology" + ], + "languages": [ + "english", + "mandarin" + ] + }, + { + "id": "DR003", + "name": "Dr. Lisa Peterson", + "role": "diabetes_specialist", + "specialties": [ + "endocrinology" + ], + "languages": [ + "english" + ] + }, + { + "id": "NP001", + "name": "Nancy Williams", + "role": "nurse_practitioner", + "specialties": [ + "primary_care" + ], + "languages": [ + "english" + ] + }, + { + "id": "RN001", + "name": "Robert Garcia", + "role": "nurse", + "specialties": [ + "geriatric_care" + ], + "languages": [ + "english", + "spanish" + ] + }, + { + "id": "MH001", + "name": "Dr. Emily Cohen", + "role": "mental_health_provider", + "specialties": [ + "psychiatry", + "geriatric_psychiatry" + ], + "languages": [ + "english" + ] + }, + { + "id": "PT001", + "name": "James Wilson", + "role": "physical_therapist", + "specialties": [ + "geriatric_physical_therapy" + ], + "languages": [ + "english" + ] + }, + { + "id": "CC001", + "name": "Maria Rodriguez", + "role": "care_coordinator", + "specialties": [ + "complex_care_coordination" + ], + "languages": [ + "english", + "spanish" + ] + } + ] + }, + "output": { + "ageCategory": "senior", + "careTeam": { + "complexityLevel": "high", + "coordinator": { + "priority": "high", + "role": "care_coordinator" + }, + "providers": [ + { + "priority": "high", + "role": "primary_physician" + }, + { + "priority": "medium", + "role": "geriatric_specialist" + }, + { + "priority": "medium", + "role": "mental_health_provider" + }, + { + "priority": "medium", + "role": "nutritionist" + }, + { + "priority": "high", + "role": "nurse_practitioner" + }, + { + "priority": "medium", + "role": "physical_therapist" + } + ], + "teamSize": "3" + }, + "mobilityIssues": true, + "requiresMentalHealthSupport": true, + "requiresNutritionSupport": true, + "requiresSpecialist": true + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "\"high\"", + "o1-1": "\"high\"", + "o1-2": "\"3\"" + }, + { + "_id": "r1-2", + "i1-1": "\"medium\"", + "o1-1": "\"medium\"", + "o1-2": "\"2\"" + }, + { + "_id": "r1-3", + "i1-1": "\"low\"", + "o1-1": "\"low\"", + "o1-2": "\"1\"" + }, + { + "_id": "r1-4", + "i1-1": "", + "o1-1": "\"low\"", + "o1-2": "\"1\"" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Care Complexity", + "field": "patient.careComplexity" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Complexity Level", + "field": "careTeam.complexityLevel" + }, + { + "id": "o1-2", + "name": "Team Size", + "field": "careTeam.teamSize" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "determine_complexity", + "position": { + "x": 430, + "y": 292.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "requiresSpecialist", + "value": "some(patient.conditions, # in ['diabetes', 'heart_disease', 'kidney_disease'])" + }, + { + "id": "e1-2", + "key": "requiresMentalHealthSupport", + "value": "some(patient.conditions, # in ['depression', 'anxiety', 'ptsd'])" + }, + { + "id": "e1-3", + "key": "requiresNutritionSupport", + "value": "some(patient.conditions, # in ['obesity', 'diabetes', 'malnutrition'])" + }, + { + "id": "e1-5", + "key": "mobilityIssues", + "value": "patient.mobilityScore < 50" + }, + { + "id": "e1-6", + "key": "patient", + "value": "null" + }, + { + "id": "e1-7", + "key": "availableProviders", + "value": "null" + }, + { + "id": "e1-8", + "key": "facility", + "value": "null" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "evaluate_patient_needs", + "position": { + "x": 1070, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "r2-1", + "i2-1": "\"high\"", + "i2-2": "", + "o2-1": "\"primary_physician\"", + "o2-2": "\"high\"", + "o2-3": "" + }, + { + "_id": "r2-2", + "i2-1": "\"medium\", \"low\"", + "i2-2": "", + "o2-1": "\"primary_physician\"", + "o2-2": "\"medium\"", + "o2-3": "" + }, + { + "_id": "r2-3", + "i2-1": "", + "i2-2": "ageCategory == \"senior\"", + "o2-1": "\"geriatric_specialist\"", + "o2-2": "\"medium\"", + "o2-3": "" + }, + { + "_id": "r2-4", + "i2-1": "", + "i2-2": "ageCategory == \"pediatric\"", + "o2-1": "\"pediatrician\"", + "o2-2": "\"medium\"", + "o2-3": "" + }, + { + "_id": "r2-5", + "i2-1": "", + "i2-2": "\"diabetes\" in patient.conditions", + "o2-1": "\"diabetes_specialist\"", + "o2-2": "\"high\"", + "o2-3": "\"diabetes\"" + }, + { + "_id": "r2-6", + "i2-1": "", + "i2-2": "\"heart_disease\" in patient.conditions", + "o2-1": "\"cardiologist\"", + "o2-2": "\"high\"", + "o2-3": "\"heart_disease\"" + }, + { + "_id": "r2-7", + "i2-1": "", + "i2-2": "\"kidney_disease\" in patient.conditions", + "o2-1": "\"nephrologist\"", + "o2-2": "\"high\"", + "o2-3": "\"kidney_disease\"" + }, + { + "_id": "r2-8", + "i2-1": "", + "i2-2": "requiresMentalHealthSupport == true", + "o2-1": "\"mental_health_provider\"", + "o2-2": "\"medium\"", + "o2-3": "" + }, + { + "_id": "r2-9", + "i2-1": "", + "i2-2": "requiresNutritionSupport == true", + "o2-1": "\"nutritionist\"", + "o2-2": "\"medium\"", + "o2-3": "" + }, + { + "_id": "r2-10", + "i2-1": "\"high\"", + "i2-2": "", + "o2-1": "\"nurse_practitioner\"", + "o2-2": "\"high\"", + "o2-3": "" + }, + { + "_id": "r2-11", + "i2-1": "\"medium\", \"low\"", + "i2-2": "", + "o2-1": "\"nurse\"", + "o2-2": "\"medium\"", + "o2-3": "" + }, + { + "_id": "r2-12", + "i2-1": "", + "i2-2": "mobilityIssues == true", + "o2-1": "\"physical_therapist\"", + "o2-2": "\"medium\"", + "o2-3": "" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Complexity Level", + "field": "careTeam.complexityLevel" + }, + { + "id": "i2-2", + "name": "Patient Condition" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Provider Role", + "field": "role" + }, + { + "id": "o2-2", + "name": "Priority", + "field": "priority" + }, + { + "id": "o2-3", + "name": "Specialty Focus", + "field": "specialtyFocus" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "careTeam.providers", + "executionMode": "single", + "passThorough": false + }, + "id": "dt2", + "name": "assign_providers", + "position": { + "x": 1390, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "\"high\"", + "i3-2": "len(careTeam.providers) > 5", + "o3-1": "\"care_coordinator\"", + "o3-2": "\"high\"" + }, + { + "_id": "r3-2", + "i3-1": "\"high\", \"medium\"", + "i3-2": "", + "o3-1": "\"case_manager\"", + "o3-2": "\"medium\"" + }, + { + "_id": "r3-3", + "i3-1": "", + "i3-2": "", + "o3-1": "\"none\"", + "o3-2": "\"low\"" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Complexity Level", + "field": "careTeam.complexityLevel" + }, + { + "id": "i3-2", + "name": "Team Size", + "field": "$" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Coordinator Role", + "field": "careTeam.coordinator.role" + }, + { + "id": "o3-2", + "name": "Coordinator Priority", + "field": "careTeam.coordinator.priority" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt3", + "name": "assign_coordinator", + "position": { + "x": 1710, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "< 18", + "o1-2": "\"pediatric\"" + }, + { + "_id": "r1-2", + "i1-1": "< 65", + "o1-2": "\"adult\"" + }, + { + "_id": "r1-3", + "i1-1": "", + "o1-2": "\"senior\"" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Patient age", + "field": "patient.age" + } + ], + "outputs": [ + { + "id": "o1-2", + "name": "Age category", + "field": "ageCategory" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "f1af25e2-126e-4882-8d35-6ae33dbc37bf", + "name": "age_category", + "position": { + "x": 750, + "y": 292.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ex1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "dt2", + "targetId": "dt3", + "type": "edge" + }, + { + "id": "c45e4da7-e948-40ba-965b-772c57497e67", + "sourceId": "dt1", + "type": "edge", + "targetId": "f1af25e2-126e-4882-8d35-6ae33dbc37bf" + }, + { + "id": "1483ea19-afcd-418e-9a8a-efbc34636b4b", + "sourceId": "f1af25e2-126e-4882-8d35-6ae33dbc37bf", + "type": "edge", + "targetId": "ex1" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/cellular-data-rollover-system.json b/test-data/graphs/cellular-data-rollover-system.json new file mode 100644 index 00000000..244a7a3a --- /dev/null +++ b/test-data/graphs/cellular-data-rollover-system.json @@ -0,0 +1,281 @@ +{ + "tests": [ + { + "input": { + "plan": { + "type": "premium", + "monthlyDataAllowance": 50, + "rolloverEligible": true + }, + "currentBillingCycle": { + "dataUsed": 35, + "consecutiveRollovers": 1, + "rolloverData": 5 + } + }, + "output": { + "nextBillingCycle": { + "consecutiveRollovers": 2, + "status": "approved" + }, + "responseMessage": "Rollover successful. You have 20 GB of rollover data available for your next billing cycle." + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "dataRolloverRequest", + "position": { + "x": 110, + "y": 212.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "unusedData", + "value": "plan.monthlyDataAllowance - currentBillingCycle.dataUsed" + }, + { + "id": "e1-2", + "key": "isPositiveUnusedData", + "value": "$.unusedData > 0" + }, + { + "id": "e1-3", + "key": "previousRolloverAmount", + "value": "currentBillingCycle.rolloverData ?? 0" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateUnusedData", + "position": { + "x": 430, + "y": 212.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'premium'", + "i1-2": "true", + "i1-3": "< 3", + "o1-1": "unusedData + previousRolloverAmount", + "o1-2": "'Unlimited rollover for Premium plan'" + }, + { + "_id": "r1-2", + "i1-1": "'standard'", + "i1-2": "true", + "i1-3": "< 3", + "o1-1": "min([unusedData + previousRolloverAmount, plan.monthlyDataAllowance * 0.5])", + "o1-2": "'Standard plan can rollover up to 50% of monthly allowance'" + }, + { + "_id": "r1-3", + "i1-1": "'basic'", + "i1-2": "true", + "i1-3": "< 3", + "o1-1": "min([unusedData, plan.monthlyDataAllowance * 0.25])", + "o1-2": "'Basic plan can rollover up to 25% of monthly allowance'" + }, + { + "_id": "r1-4", + "i1-1": "", + "i1-2": "true", + "i1-3": ">= 3", + "o1-1": "0", + "o1-2": "'Maximum consecutive rollovers (3) reached'" + }, + { + "_id": "r1-5", + "i1-1": "", + "i1-2": "false", + "i1-3": "", + "o1-1": "0", + "o1-2": "'No unused data to rollover'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Plan Type", + "field": "plan.type" + }, + { + "id": "i1-2", + "name": "Has Unused Data", + "field": "isPositiveUnusedData" + }, + { + "id": "i1-3", + "name": "Consecutive Rollovers", + "field": "currentBillingCycle.consecutiveRollovers" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Rollover Amount", + "field": "nextBillingCycle.rolloverData" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "nextBillingCycle.rolloverReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt1", + "name": "determineRolloverAmount", + "position": { + "x": 750, + "y": 212.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "s1-1", + "condition": "nextBillingCycle.rolloverData > 0", + "isDefault": false + }, + { + "id": "s1-2", + "condition": "", + "isDefault": true + } + ] + }, + "id": "sw1", + "name": "verifyRollover", + "position": { + "x": 1070, + "y": 212.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e2-1", + "key": "responseMessage", + "value": "`Rollover successful. You have ${nextBillingCycle.rolloverData} GB of rollover data available for your next billing cycle.`" + }, + { + "id": "e2-2", + "key": "nextBillingCycle.consecutiveRollovers", + "value": "currentBillingCycle.consecutiveRollovers + 1" + }, + { + "id": "e2-3", + "key": "nextBillingCycle.status", + "value": "'approved'" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex2", + "name": "processSuccessfulRollover", + "position": { + "x": 1390, + "y": 163.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e3-1", + "key": "responseMessage", + "value": "`No data rolled over. Reason: ${nextBillingCycle.rolloverReason ?? 'No unused data available'}`" + }, + { + "id": "e3-2", + "key": "nextBillingCycle.consecutiveRollovers", + "value": "0" + }, + { + "id": "e3-3", + "key": "nextBillingCycle.status", + "value": "'no_rollover'" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex3", + "name": "processNoRollover", + "position": { + "x": 1390, + "y": 261.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ex1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt1", + "targetId": "sw1", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "sw1", + "targetId": "ex2", + "sourceHandle": "s1-1", + "type": "edge" + }, + { + "id": "ed5", + "sourceId": "sw1", + "targetId": "ex3", + "sourceHandle": "s1-2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/claim-validation-system.json b/test-data/graphs/claim-validation-system.json new file mode 100644 index 00000000..1d1a4971 --- /dev/null +++ b/test-data/graphs/claim-validation-system.json @@ -0,0 +1,307 @@ +{ + "tests": [ + { + "input": { + "claimNumber": "CLM12345", + "policyNumber": "POL98765432", + "policyStatus": "active", + "policyStartDate": 1609459200, + "incidentDate": 1640995200, + "damageAmount": 1500, + "claimType": "property", + "description": "Water damage from burst pipe in kitchen" + }, + "output": { + "claimNumber": "CLM12345", + "claimType": "property", + "damageAmount": 1500, + "description": "Water damage from burst pipe in kitchen", + "incidentDate": 1640995200, + "isValid": false, + "nextStep": "rejection", + "policyNumber": "POL98765432", + "policyStartDate": 1609459200, + "policyStatus": "active", + "validation": { + "claimDetailsReason": "", + "claimDetailsValid": true, + "policyStatusValid": true, + "timeframesReason": "Claim reported more than 60 days after incident", + "timeframesValid": false + }, + "validationMessage": "Claim reported more than 60 days after incident" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "claimRequest", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "len(trim(claimNumber ?? '')) < 5", + "o1-1": "false", + "o1-2": "'Invalid claim number format'" + }, + { + "_id": "r1-2", + "i1-1": "type(incidentDate) != 'number'", + "o1-1": "false", + "o1-2": "'Incident date is missing or invalid'" + }, + { + "_id": "r1-3", + "i1-1": "len(trim(policyNumber ?? '')) < 8", + "o1-1": "false", + "o1-2": "'Invalid policy number format'" + }, + { + "_id": "r1-4", + "i1-1": "damageAmount <= 0", + "o1-1": "false", + "o1-2": "'Damage amount must be greater than zero'" + }, + { + "_id": "r1-5", + "i1-1": "", + "o1-1": "true", + "o1-2": "''" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Input" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "IsValid", + "field": "validation.claimDetailsValid" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "validation.claimDetailsReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "validateClaimDetails", + "name": "validateClaimDetails", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "!validation.claimDetailsValid", + "o2-1": "false", + "o2-2": "validation.claimDetailsReason" + }, + { + "_id": "r2-2", + "i2-1": "policyStatus == 'expired'", + "o2-1": "false", + "o2-2": "'Policy has expired'" + }, + { + "_id": "r2-3", + "i2-1": "policyStatus == 'canceled'", + "o2-1": "false", + "o2-2": "'Policy has been canceled'" + }, + { + "_id": "r2-4", + "i2-1": "policyStatus == 'suspended'", + "o2-1": "false", + "o2-2": "'Policy is currently suspended'" + }, + { + "_id": "r2-5", + "i2-1": "", + "o2-1": "true", + "o2-2": "" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Input" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "IsValid", + "field": "validation.policyStatusValid" + }, + { + "id": "o2-2", + "name": "Reason", + "field": "validation.policyStatusReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "checkPolicyStatus", + "name": "checkPolicyStatus", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "!validation.policyStatusValid", + "o3-1": "false", + "o3-2": "validation.policyStatusReason" + }, + { + "_id": "r3-2", + "i3-1": "date('now') - incidentDate > 60 * 24 * 60 * 60", + "o3-1": "false", + "o3-2": "'Claim reported more than 60 days after incident'" + }, + { + "_id": "r3-3", + "i3-1": "incidentDate > date('now')", + "o3-1": "false", + "o3-2": "'Incident date cannot be in the future'" + }, + { + "_id": "r3-4", + "i3-1": "policyStartDate > incidentDate", + "o3-1": "false", + "o3-2": "'Incident occurred before policy start date'" + }, + { + "_id": "r3-5", + "i3-1": "", + "o3-1": "true", + "o3-2": "''" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Input" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "IsValid", + "field": "validation.timeframesValid" + }, + { + "id": "o3-2", + "name": "Reason", + "field": "validation.timeframesReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "evaluateTimeframes", + "name": "evaluateTimeframes", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "isValid", + "value": "validation.claimDetailsValid and validation.policyStatusValid and validation.timeframesValid" + }, + { + "id": "e1-2", + "key": "validationMessage", + "value": "validation.claimDetailsValid ? (validation.policyStatusValid ? (validation.timeframesValid ? 'Claim validation passed' : validation.timeframesReason) : validation.policyStatusReason) : validation.claimDetailsReason" + }, + { + "id": "e1-3", + "key": "nextStep", + "value": "$.isValid ? 'investigation' : 'rejection'" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "determineOutcome", + "name": "determineOutcome", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "e1", + "sourceId": "input", + "targetId": "validateClaimDetails", + "type": "edge" + }, + { + "id": "e2", + "sourceId": "validateClaimDetails", + "targetId": "checkPolicyStatus", + "type": "edge" + }, + { + "id": "e3", + "sourceId": "checkPolicyStatus", + "targetId": "evaluateTimeframes", + "type": "edge" + }, + { + "id": "e4", + "sourceId": "evaluateTimeframes", + "targetId": "determineOutcome", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/clinical-lab-result-interpreter.json b/test-data/graphs/clinical-lab-result-interpreter.json new file mode 100644 index 00000000..0d39a2ac --- /dev/null +++ b/test-data/graphs/clinical-lab-result-interpreter.json @@ -0,0 +1,433 @@ +{ + "tests": [ + { + "input": { + "testResults": [ + { + "testType": "glucose", + "value": 260, + "date": "2025-03-15" + }, + { + "testType": "potassium", + "value": 3.2, + "date": "2025-03-15" + }, + { + "testType": "hemoglobin", + "value": 10.2, + "date": "2025-03-15" + }, + { + "testType": "creatinine", + "value": 1.7, + "date": "2025-03-15" + } + ], + "patientHistory": { + "conditions": [ + "diabetes", + "hypertension" + ], + "medications": [ + "metformin", + "lisinopril", + "atorvastatin" + ], + "allergies": [ + "penicillin" + ] + } + }, + "output": { + "followUp": { + "actionRequired": "Immediate provider notification required", + "timeframe": "24 hours" + }, + "patientHistory": { + "allergies": [ + "penicillin" + ], + "conditions": [ + "diabetes", + "hypertension" + ], + "medications": [ + "metformin", + "lisinopril", + "atorvastatin" + ] + }, + "riskAssessment": { + "clinicalRecommendation": "Schedule follow-up within 48 hours; consider insulin adjustment", + "level": "high-risk" + }, + "testResults": [ + { + "condition": "Hyperglycemia", + "date": "2025-03-15", + "flag": "abnormal", + "recommendation": "Monitor closely; adjust diabetes management if applicable", + "testType": "glucose", + "value": 260 + }, + { + "condition": "Hypokalemia", + "date": "2025-03-15", + "flag": "critical", + "recommendation": "Urgent electrolyte replacement; ECG monitoring required", + "testType": "potassium", + "value": 3.2 + }, + { + "date": "2025-03-15", + "testType": "hemoglobin", + "value": 10.2 + }, + { + "condition": "Elevated Creatinine", + "date": "2025-03-15", + "flag": "abnormal", + "recommendation": "Evaluate kidney function; adjust medication dosages as needed", + "testType": "creatinine", + "value": 1.7 + } + ], + "urgencyLevel": "urgent" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "labResults", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "< 3.5", + "i1-2": "'potassium'", + "o1-1": "'critical'", + "o1-2": "'Hypokalemia'", + "o1-3": "'Urgent electrolyte replacement; ECG monitoring required'" + }, + { + "_id": "r1-2", + "i1-1": "> 6.0", + "i1-2": "'potassium'", + "o1-1": "'critical'", + "o1-2": "'Hyperkalemia'", + "o1-3": "'Urgent intervention required; cardiac monitoring advised'" + }, + { + "_id": "r1-3", + "i1-1": "< 8.5", + "i1-2": "'hemoglobin'", + "o1-1": "'abnormal'", + "o1-2": "'Anemia'", + "o1-3": "'Evaluate for blood loss or chronic disease'" + }, + { + "_id": "r1-4", + "i1-1": "> 18.0", + "i1-2": "'hemoglobin'", + "o1-1": "'abnormal'", + "o1-2": "'Polycythemia'", + "o1-3": "'Evaluate for underlying conditions'" + }, + { + "_id": "r1-5", + "i1-1": "> 200", + "i1-2": "'glucose'", + "o1-1": "'abnormal'", + "o1-2": "'Hyperglycemia'", + "o1-3": "'Monitor closely; adjust diabetes management if applicable'" + }, + { + "_id": "r1-6", + "i1-1": "< 70", + "i1-2": "'glucose'", + "o1-1": "'critical'", + "o1-2": "'Hypoglycemia'", + "o1-3": "'Immediate glucose administration; evaluate medication regimen'" + }, + { + "_id": "r1-7", + "i1-1": "> 1.5", + "i1-2": "'creatinine'", + "o1-1": "'abnormal'", + "o1-2": "'Elevated Creatinine'", + "o1-3": "'Evaluate kidney function; adjust medication dosages as needed'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Value", + "field": "value" + }, + { + "id": "i1-2", + "name": "Test Type", + "field": "testType" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Flag", + "field": "flag" + }, + { + "id": "o1-2", + "name": "Condition", + "field": "condition" + }, + { + "id": "o1-3", + "name": "Recommendation", + "field": "recommendation" + } + ], + "passThrough": true, + "inputField": "testResults", + "outputPath": "testResults", + "executionMode": "loop" + }, + "id": "dt1", + "name": "basicLabEvaluation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'diabetes' in $", + "i2-2": "some($, # in ['metformin', 'insulin', 'glipizide'])", + "i2-3": "some(testResults, #.testType == 'glucose' and #.value > 250)", + "o2-1": "'high-risk'", + "o2-2": "'Schedule follow-up within 48 hours; consider insulin adjustment'" + }, + { + "_id": "r2-2", + "i2-1": "'heart_failure' in $", + "i2-2": "some($, # in ['furosemide', 'spironolactone'])", + "i2-3": "some(testResults, #.testType == 'potassium' and #.value > 3.0)", + "o2-1": "'high-risk'", + "o2-2": "'Urgent electrolyte replacement; evaluate diuretic dosage'" + }, + { + "_id": "r2-3", + "i2-1": "'kidney_disease' in $", + "i2-2": "", + "i2-3": "some(testResults, #.testType == 'creatinine' and #.value > 2.0)\n", + "o2-1": "'high-risk'", + "o2-2": "'Nephrology consult; adjust medication dosages'" + }, + { + "_id": "r2-4", + "i2-1": "", + "i2-2": "'warfarin' in $", + "i2-3": "some(testResults, #.testType == 'inr' and #.value > 3.5)", + "o2-1": "'high-risk'", + "o2-2": "'Hold next warfarin dose; monitor for bleeding'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Condition", + "field": "patientHistory.conditions" + }, + { + "id": "i2-2", + "name": "Medications", + "field": "patientHistory.medications" + }, + { + "id": "i2-3", + "name": "Additional condition" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Risk Level", + "field": "riskAssessment.level" + }, + { + "id": "o2-2", + "name": "Clinical Recommendation", + "field": "riskAssessment.clinicalRecommendation" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "patientContextEvaluation", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r4-1", + "i4-1": "some(testResults, #.flag == 'critical')", + "o4-1": "'urgent'" + }, + { + "_id": "r4-2", + "i4-1": "riskAssessment.level == 'high-risk'", + "o4-1": "'high'" + }, + { + "_id": "r4-3", + "i4-1": "some(testResults, #.flag == 'abnormal')", + "o4-1": "'moderate'" + }, + { + "_id": "r4-4", + "i4-1": "", + "o4-1": "'routine'" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "Condition" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "Urgency Level", + "field": "urgencyLevel" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt4", + "name": "urgencyAssessment", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "'urgent'", + "o3-1": "'Immediate provider notification required'", + "o3-2": "'24 hours'" + }, + { + "_id": "r3-2", + "i3-1": "'high'", + "o3-1": "'Provider notification recommended'", + "o3-2": "'72 hours'" + }, + { + "_id": "r3-3", + "i3-1": "'moderate'", + "o3-1": "'Include in routine provider review'", + "o3-2": "'1 week'" + }, + { + "_id": "r3-4", + "i3-1": "'routine'", + "o3-1": "'No immediate action required'", + "o3-2": "'Next scheduled visit'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Urgency", + "field": "urgencyLevel" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Action Required", + "field": "followUp.actionRequired" + }, + { + "id": "o3-2", + "name": "Timeframe", + "field": "followUp.timeframe" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt3", + "name": "followUpDetermination", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt2", + "targetId": "dt4", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "dt4", + "targetId": "dt3", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/clinical-pathway-selection.json b/test-data/graphs/clinical-pathway-selection.json new file mode 100644 index 00000000..476f2dae --- /dev/null +++ b/test-data/graphs/clinical-pathway-selection.json @@ -0,0 +1,454 @@ +{ + "tests": [ + { + "input": { + "patient": { + "id": "P1234567", + "primaryDiagnosis": "heart_failure", + "severityScore": 3, + "age": 72, + "bmi": 24, + "comorbidities": [ + "diabetes", + "hypertension", + "kidney_disease" + ], + "currentMedications": [ + { + "name": "Lisinopril", + "dosage": "10mg", + "frequency": "daily" + }, + { + "name": "Metformin", + "dosage": "500mg", + "frequency": "twice daily" + }, + { + "name": "Furosemide", + "dosage": "40mg", + "frequency": "daily" + } + ], + "vitalSigns": { + "bloodPressure": { + "systolic": 142, + "diastolic": 85 + }, + "heartRate": 88, + "oxygenSaturation": 94, + "temperature": 37.1 + }, + "labResults": { + "bnp": 450, + "creatinine": 1.4, + "potassium": 4.2, + "hba1c": 7.8 + } + } + }, + "output": { + "followupFrequency": "daily", + "recommendedMonitoring": [ + "comprehensive_vitals", + "medication_adherence", + "lifestyle_factors", + "specialist_consultation" + ], + "selectedPathway": "intensive" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 136.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "'heart_failure'", + "i2": "> 2", + "o1": "'cardiac'", + "o2": "8" + }, + { + "_id": "r2", + "i1": "'heart_failure'", + "i2": "", + "o1": "'cardiac'", + "o2": "5" + }, + { + "_id": "r3", + "i1": "'pneumonia'", + "i2": "> 1", + "o1": "'respiratory'", + "o2": "7" + }, + { + "_id": "r4", + "i1": "'pneumonia'", + "i2": "", + "o1": "'respiratory'", + "o2": "4" + }, + { + "_id": "r5", + "i1": "'diabetes'", + "i2": "> 8.5", + "o1": "'endocrine'", + "o2": "6" + }, + { + "_id": "r6", + "i1": "'diabetes'", + "i2": "", + "o1": "'endocrine'", + "o2": "3" + }, + { + "_id": "r7", + "i1": "'stroke'", + "i2": "> 1", + "o1": "'neurological'", + "o2": "9" + }, + { + "_id": "r8", + "i1": "'stroke'", + "i2": "", + "o1": "'neurological'", + "o2": "6" + }, + { + "_id": "r9", + "i1": "", + "i2": "", + "o1": "'general'", + "o2": "2" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Primary Diagnosis", + "field": "patient.primaryDiagnosis" + }, + { + "id": "i2", + "name": "Severity Score", + "field": "patient.severityScore" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Clinical Domain", + "field": "evaluation.clinicalDomain" + }, + { + "id": "o2", + "name": "Base Risk Score", + "field": "evaluation.baseRiskScore" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "diagnoseTable", + "name": "diagnosisEvaluation", + "position": { + "x": 430, + "y": 136.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "comorbidityCount", + "value": "len(patient.comorbidities ?? [])" + }, + { + "id": "e2", + "key": "hasHighRiskComorbidity", + "value": "contains(patient.comorbidities ?? [], 'kidney_disease') or contains(patient.comorbidities ?? [], 'copd') or contains(patient.comorbidities ?? [], 'immunocompromised')" + }, + { + "id": "e3", + "key": "comorbidityRiskScore", + "value": "$.comorbidityCount * 2 + ($.hasHighRiskComorbidity ? 3 : 0)" + }, + { + "id": "e4", + "key": "totalRiskScore", + "value": "evaluation.baseRiskScore + $.comorbidityRiskScore" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "comorbidityCheck", + "name": "comorbidityEvaluation", + "position": { + "x": 750, + "y": 136.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "> 80", + "i2": "< 20", + "o1": "3", + "o2": "'high'" + }, + { + "_id": "r2", + "i1": "> 70", + "i2": "< 25", + "o1": "2", + "o2": "'moderate'" + }, + { + "_id": "r3", + "i1": "", + "i2": "", + "o1": "0", + "o2": "'standard'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Age", + "field": "patient.age" + }, + { + "id": "i2", + "name": "BMI", + "field": "patient.bmi" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Additional Risk Score", + "field": "evaluation.additionalRiskScore" + }, + { + "id": "o2", + "name": "Patient Risk Category", + "field": "evaluation.patientRiskCategory" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "patientFactorsTable", + "name": "patientFactorsEvaluation", + "position": { + "x": 1070, + "y": 136.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "intensive", + "condition": "totalRiskScore + evaluation.additionalRiskScore >= 12", + "isDefault": false + }, + { + "id": "enhanced", + "condition": "totalRiskScore + evaluation.additionalRiskScore >= 8", + "isDefault": false + }, + { + "id": "standard", + "condition": "", + "isDefault": true + } + ] + }, + "id": "finalPathwaySwitch", + "name": "pathwaySelection", + "position": { + "x": 1390, + "y": 136.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "selectedPathway", + "value": "'standard'" + }, + { + "id": "e2", + "key": "followupFrequency", + "value": "'weekly'" + }, + { + "id": "e3", + "key": "recommendedMonitoring", + "value": "['basic_vitals', 'medication_adherence']" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "standardPathway", + "name": "standardPathway", + "position": { + "x": 1710, + "y": 385 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "selectedPathway", + "value": "'enhanced'" + }, + { + "id": "e2", + "key": "followupFrequency", + "value": "'twice_weekly'" + }, + { + "id": "e3", + "key": "recommendedMonitoring", + "value": "['extended_vitals', 'medication_adherence', 'lifestyle_factors']" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "enhancedPathway", + "name": "enhancedPathway", + "position": { + "x": 1710, + "y": 280 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "selectedPathway", + "value": "'intensive'" + }, + { + "id": "e2", + "key": "followupFrequency", + "value": "'daily'" + }, + { + "id": "e3", + "key": "recommendedMonitoring", + "value": "['comprehensive_vitals', 'medication_adherence', 'lifestyle_factors', 'specialist_consultation']" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "intensivePathway", + "name": "intensivePathway", + "position": { + "x": 1710, + "y": 170 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "diagnoseTable", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "diagnoseTable", + "targetId": "comorbidityCheck", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "comorbidityCheck", + "targetId": "patientFactorsTable", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "patientFactorsTable", + "targetId": "finalPathwaySwitch", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "finalPathwaySwitch", + "targetId": "standardPathway", + "sourceHandle": "standard", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "finalPathwaySwitch", + "targetId": "enhancedPathway", + "sourceHandle": "enhanced", + "type": "edge" + }, + { + "id": "edge7", + "sourceId": "finalPathwaySwitch", + "targetId": "intensivePathway", + "sourceHandle": "intensive", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/clinical-treatment-protocol.json b/test-data/graphs/clinical-treatment-protocol.json new file mode 100644 index 00000000..94b75146 --- /dev/null +++ b/test-data/graphs/clinical-treatment-protocol.json @@ -0,0 +1,474 @@ +{ + "tests": [ + { + "input": { + "diagnosis": "diabetes_type2", + "measurement_value": 8.2, + "patient": { + "age": 67, + "is_pregnant": "no", + "has_comorbidities": "yes", + "previous_adverse_reaction": "no" + } + }, + "output": { + "protocol_name": "oral_medication_moderate", + "treatment_protocol": { + "base_treatment": "oral_medication", + "dosage_instruction": "standard_elderly", + "follow_up_frequency": "bi-weekly", + "protocol_id": "oral_medication_moderate_intensive", + "protocol_intensity": "intensive", + "risk_adjustment": "modified_treatment", + "severity_level": "moderate_diabetes" + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1-1": "'diabetes_type2'", + "i1-2": "< 7.0", + "o1-1": "'mild_diabetes'", + "o1-2": "'lifestyle_modification'" + }, + { + "_id": "rule2", + "i1-1": "'diabetes_type2'", + "i1-2": "[7.0..8.5]", + "o1-1": "'moderate_diabetes'", + "o1-2": "'oral_medication'" + }, + { + "_id": "rule3", + "i1-1": "'diabetes_type2'", + "i1-2": "> 8.5", + "o1-1": "'severe_diabetes'", + "o1-2": "'insulin_therapy'" + }, + { + "_id": "rule4", + "i1-1": "'hypertension'", + "i1-2": "[140..160)", + "o1-1": "'stage1_hypertension'", + "o1-2": "'lifestyle_and_monotherapy'" + }, + { + "_id": "rule5", + "i1-1": "'hypertension'", + "i1-2": ">= 160", + "o1-1": "'stage2_hypertension'", + "o1-2": "'dual_therapy'" + }, + { + "_id": "rule6", + "i1-1": "'asthma'", + "i1-2": "> 80", + "o1-1": "'mild_asthma'", + "o1-2": "'as_needed_bronchodilator'" + }, + { + "_id": "rule7", + "i1-1": "'asthma'", + "i1-2": "[60..80]", + "o1-1": "'moderate_asthma'", + "o1-2": "'daily_controller'" + }, + { + "_id": "rule8", + "i1-1": "'asthma'", + "i1-2": "< 60", + "o1-1": "'severe_asthma'", + "o1-2": "'multiple_controllers'" + }, + { + "_id": "rule9", + "i1-1": "", + "i1-2": "", + "o1-1": "'unclassified'", + "o1-2": "'standard_care'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Diagnosis", + "field": "diagnosis" + }, + { + "id": "i1-2", + "name": "MeasurementValue", + "field": "measurement_value" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Severity", + "field": "diagnosis_severity" + }, + { + "id": "o1-2", + "name": "BaseTreatment", + "field": "base_treatment" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "diagnoseTable", + "name": "diagnosisEvaluation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "pc1", + "i2-1": ">= 65", + "i2-2": "'yes'", + "o2-1": "'high'", + "o2-2": "'reduced_dosage'" + }, + { + "_id": "pc2", + "i2-1": ">= 65", + "i2-2": "'no'", + "o2-1": "'moderate'", + "o2-2": "'standard_elderly'" + }, + { + "_id": "pc3", + "i2-1": "< 18", + "i2-2": "", + "o2-1": "'special'", + "o2-2": "'pediatric_dosage'" + }, + { + "_id": "pc4", + "i2-1": "", + "i2-2": "'yes'", + "o2-1": "'elevated'", + "o2-2": "'monitor_closely'" + }, + { + "_id": "pc5", + "i2-1": "", + "i2-2": "", + "o2-1": "'standard'", + "o2-2": "'standard_dosage'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Age", + "field": "patient.age" + }, + { + "id": "i2-2", + "name": "Pregnancy", + "field": "patient.is_pregnant" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "PatientRiskCategory", + "field": "patient_risk_category" + }, + { + "id": "o2-2", + "name": "DosageModification", + "field": "dosage_modification" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "patientCharacteristics", + "name": "patientFactors", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rf1", + "i3-1": "'yes'", + "i3-2": "'yes'", + "o3-1": "'critical'", + "o3-2": "'specialist_consult'" + }, + { + "_id": "rf2", + "i3-1": "'yes'", + "i3-2": "'no'", + "o3-1": "'high'", + "o3-2": "'modified_treatment'" + }, + { + "_id": "rf3", + "i3-1": "'no'", + "i3-2": "'yes'", + "o3-1": "'moderate'", + "o3-2": "'additional_monitoring'" + }, + { + "_id": "rf4", + "i3-1": "'no'", + "i3-2": "'no'", + "o3-1": "'low'", + "o3-2": "'standard_approach'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "HasComorbidities", + "field": "patient.has_comorbidities" + }, + { + "id": "i3-2", + "name": "PreviousAdverseReaction", + "field": "patient.previous_adverse_reaction" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "ComorbidityRiskLevel", + "field": "comorbidity_risk_level" + }, + { + "id": "o3-2", + "name": "RiskAdjustment", + "field": "risk_adjustment" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "riskFactors", + "name": "comorbidityEvaluation", + "position": { + "x": 1070, + "y": 115 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "pi1", + "i4-1": "'critical'", + "o4-1": "'urgent'" + }, + { + "_id": "pi2", + "i4-1": "'high'", + "o4-1": "'intensive'" + }, + { + "_id": "pi3", + "i4-1": "'moderate'", + "o4-1": "'standard'" + }, + { + "_id": "pi4", + "i4-1": "'low'", + "o4-1": "'routine'" + }, + { + "_id": "pi5", + "i4-1": "", + "o4-1": "'regular'" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "RiskLevel", + "field": "comorbidity_risk_level" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "ProtocolIntensity", + "field": "protocol_intensity" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "protocolIntensity", + "name": "intensityDetermination", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "fs1", + "i5-1": "'critical'", + "o5-1": "'weekly'" + }, + { + "_id": "fs2", + "i5-1": "'high'", + "o5-1": "'bi-weekly'" + }, + { + "_id": "fs3", + "i5-1": "'moderate'", + "o5-1": "'monthly'" + }, + { + "_id": "fs4", + "i5-1": "'low'", + "o5-1": "'quarterly'" + }, + { + "_id": "fs5", + "i5-1": "", + "o5-1": "'as_needed'" + } + ], + "inputs": [ + { + "id": "i5-1", + "name": "RiskLevel", + "field": "comorbidity_risk_level" + } + ], + "outputs": [ + { + "id": "o5-1", + "name": "FollowUpSchedule", + "field": "follow_up_schedule" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "followUpSchedule", + "name": "followUpDetermination", + "position": { + "x": 1710, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "exp1", + "key": "protocol_name", + "value": "base_treatment + '_' + patient_risk_category" + }, + { + "id": "exp2", + "key": "treatment_protocol", + "value": "{\n 'protocol_id': `${$.protocol_name}_${protocol_intensity}`,\n 'base_treatment': base_treatment,\n 'dosage_instruction': dosage_modification,\n 'risk_adjustment': risk_adjustment,\n 'follow_up_frequency': follow_up_schedule,\n 'severity_level': diagnosis_severity,\n 'protocol_intensity': protocol_intensity\n}" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "treatmentProtocol", + "name": "finalTreatmentSelection", + "position": { + "x": 2030, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "diagnoseTable", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "diagnoseTable", + "targetId": "patientCharacteristics", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "patientCharacteristics", + "targetId": "riskFactors", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "riskFactors", + "targetId": "protocolIntensity", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "protocolIntensity", + "targetId": "followUpSchedule", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "followUpSchedule", + "targetId": "treatmentProtocol", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/clinical-trial-eligibility-screener.json b/test-data/graphs/clinical-trial-eligibility-screener.json new file mode 100644 index 00000000..805bb190 --- /dev/null +++ b/test-data/graphs/clinical-trial-eligibility-screener.json @@ -0,0 +1,502 @@ +{ + "tests": [ + { + "input": { + "patient": { + "id": "P67890", + "name": "John Smith", + "age": 68, + "diagnosis": "lung_cancer", + "diseaseStage": "IV", + "currentMedications": [ + "immunosuppressants", + "albuterol", + "omeprazole" + ], + "priorTreatments": 3, + "comorbidities": [ + "autoimmune_disease", + "COPD" + ], + "lastLabResults": { + "wbc": 3.8, + "hgb": 10.9, + "plt": 150, + "creatinine": 1.2 + } + } + }, + "output": { + "decisionSummary": "Patient is not eligible for clinical trial", + "eligibilityReasons": [ + { + "flag": false, + "reason": "Patient taking excluded medications" + }, + { + "flag": true, + "reason": "Age within eligible range" + }, + { + "flag": false, + "reason": "Excluded comorbidity present" + }, + { + "flag": false, + "reason": "Stage IV patients excluded from trial" + }, + { + "flag": true, + "reason": "Diagnosis matches trial criteria" + }, + { + "flag": false, + "reason": "Too many prior treatments" + } + ], + "failedCriteria": [ + "medication", + "comorbidity", + "stage", + "priorTreatment" + ], + "isEligible": false + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "inputNode", + "name": "patient", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "diagnosis": "'breast_cancer', 'lung_cancer', 'colorectal_cancer'", + "diagnosisFlag": "true", + "diagnosisReason": "'Diagnosis matches trial criteria'" + }, + { + "_id": "rule2", + "diagnosis": "", + "diagnosisFlag": "false", + "diagnosisReason": "'Diagnosis does not match trial criteria'" + } + ], + "inputs": [ + { + "id": "diagnosis", + "name": "Diagnosis", + "field": "patient.diagnosis" + } + ], + "outputs": [ + { + "id": "diagnosisFlag", + "name": "DiagnosisFlag", + "field": "eligibility.diagnosis.flag" + }, + { + "id": "diagnosisReason", + "name": "DiagnosisReason", + "field": "eligibility.diagnosis.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "diagnosisEligibility", + "name": "diagnosisEligibility", + "position": { + "x": 430, + "y": -131 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "stage": "'I', 'II', 'III'", + "stageFlag": "true", + "stageReason": "'Disease stage matches trial criteria'" + }, + { + "_id": "rule2", + "stage": "'IV'", + "stageFlag": "false", + "stageReason": "'Stage IV patients excluded from trial'" + }, + { + "_id": "rule3", + "stage": "", + "stageFlag": "false", + "stageReason": "'Unknown or invalid disease stage'" + } + ], + "inputs": [ + { + "id": "stage", + "name": "Stage", + "field": "patient.diseaseStage" + } + ], + "outputs": [ + { + "id": "stageFlag", + "name": "StageFlag", + "field": "eligibility.stage.flag" + }, + { + "id": "stageReason", + "name": "StageReason", + "field": "eligibility.stage.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "diseaseStageEligibility", + "name": "diseaseStageEligibility", + "position": { + "x": 430, + "y": -33 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "medications": "some($, # in ['immunosuppressants', 'anticancer_agents', 'corticosteroids'])", + "medicationFlag": "false", + "medicationReason": "'Patient taking excluded medications'" + }, + { + "_id": "rule2", + "medications": "", + "medicationFlag": "true", + "medicationReason": "'No conflicting medications'" + } + ], + "inputs": [ + { + "id": "medications", + "name": "Medications", + "field": "patient.currentMedications ?? []" + } + ], + "outputs": [ + { + "id": "medicationFlag", + "name": "MedicationFlag", + "field": "eligibility.medication.flag" + }, + { + "id": "medicationReason", + "name": "MedicationReason", + "field": "eligibility.medication.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "medicationEligibility", + "name": "medicationEligibility", + "position": { + "x": 430, + "y": 65 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "age": ")18..75(", + "ageFlag": "false", + "ageReason": "'Age outside eligible range (18-75)'" + }, + { + "_id": "rule2", + "age": "", + "ageFlag": "true", + "ageReason": "'Age within eligible range'" + } + ], + "inputs": [ + { + "id": "age", + "name": "PatientAge", + "field": "patient.age" + } + ], + "outputs": [ + { + "id": "ageFlag", + "name": "AgeFlag", + "field": "eligibility.age.flag" + }, + { + "id": "ageReason", + "name": "AgeReason", + "field": "eligibility.age.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "ageEligibility", + "name": "ageEligibility", + "position": { + "x": 430, + "y": 163 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "priorTreatments": "> 2", + "treatmentFlag": "false", + "treatmentReason": "'Too many prior treatments'" + }, + { + "_id": "rule2", + "priorTreatments": "<= 2", + "treatmentFlag": "true", + "treatmentReason": "'Acceptable number of prior treatments'" + }, + { + "_id": "rule3", + "priorTreatments": "", + "treatmentFlag": "true", + "treatmentReason": "'No prior treatments recorded'" + } + ], + "inputs": [ + { + "id": "priorTreatments", + "name": "PriorTreatments", + "field": "patient.priorTreatments" + } + ], + "outputs": [ + { + "id": "treatmentFlag", + "name": "TreatmentFlag", + "field": "eligibility.priorTreatment.flag" + }, + { + "id": "treatmentReason", + "name": "TreatmentReason", + "field": "eligibility.priorTreatment.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "priorTreatmentEligibility", + "name": "priorTreatmentEligibility", + "position": { + "x": 430, + "y": 261 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "comorbidities": "some($, # in ['autoimmune_disease', 'heart_failure', 'uncontrolled_diabetes'])", + "comorbidityFlag": "false", + "comorbidityReason": "'Excluded comorbidity present'" + }, + { + "_id": "rule2", + "comorbidities": "", + "comorbidityFlag": "true", + "comorbidityReason": "'No exclusionary comorbidities'" + } + ], + "inputs": [ + { + "id": "comorbidities", + "name": "Comorbidities", + "field": "patient.comorbidities ?? []" + } + ], + "outputs": [ + { + "id": "comorbidityFlag", + "name": "ComorbidityFlag", + "field": "eligibility.comorbidity.flag" + }, + { + "id": "comorbidityReason", + "name": "ComorbidityReason", + "field": "eligibility.comorbidity.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "comorbidityEligibility", + "name": "comorbidityEligibility", + "position": { + "x": 430, + "y": 359 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "isEligible", + "value": "all(values(eligibility), #.flag)" + }, + { + "id": "expr2", + "key": "eligibilityReasons", + "value": "filter(values(eligibility), #.reason != null)" + }, + { + "id": "expr3", + "key": "decisionSummary", + "value": "$.isEligible ? 'Patient is eligible for clinical trial' : 'Patient is not eligible for clinical trial'" + }, + { + "id": "expr4", + "key": "failedCriteria", + "value": "filter(keys(eligibility), eligibility[#].flag == false)" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "eligibilitySummary", + "name": "eligibilitySummary", + "position": { + "x": 750, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "inputNode", + "targetId": "diagnosisEligibility", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "inputNode", + "targetId": "diseaseStageEligibility", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "inputNode", + "targetId": "medicationEligibility", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "inputNode", + "targetId": "ageEligibility", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "inputNode", + "targetId": "priorTreatmentEligibility", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "inputNode", + "targetId": "comorbidityEligibility", + "type": "edge" + }, + { + "id": "edge7", + "sourceId": "diagnosisEligibility", + "targetId": "eligibilitySummary", + "type": "edge" + }, + { + "id": "edge8", + "sourceId": "diseaseStageEligibility", + "targetId": "eligibilitySummary", + "type": "edge" + }, + { + "id": "edge9", + "sourceId": "medicationEligibility", + "targetId": "eligibilitySummary", + "type": "edge" + }, + { + "id": "edge10", + "sourceId": "ageEligibility", + "targetId": "eligibilitySummary", + "type": "edge" + }, + { + "id": "edge11", + "sourceId": "priorTreatmentEligibility", + "targetId": "eligibilitySummary", + "type": "edge" + }, + { + "id": "edge12", + "sourceId": "comorbidityEligibility", + "targetId": "eligibilitySummary", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/credit-limit-adjustment.json b/test-data/graphs/credit-limit-adjustment.json new file mode 100644 index 00000000..283190aa --- /dev/null +++ b/test-data/graphs/credit-limit-adjustment.json @@ -0,0 +1,479 @@ +{ + "tests": [ + { + "input": { + "account": { + "customer_id": "CUST10025", + "current_credit_limit": 5000, + "payment_history": { + "on_time_payment_percentage": 98, + "late_payments_last_12_months": 0, + "total_payments": 24 + }, + "utilization": { + "current_percentage": 25, + "average_last_6_months": 40, + "highest_balance": 2800 + }, + "financial_behavior": { + "credit_inquiries_last_12_months": 0, + "years_with_institution": 4, + "income_verified": true, + "has_other_products": true + } + } + }, + "output": { + "recommendation": { + "amount_change": 1500, + "new_credit_limit": 6500 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "inputNode", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1-1": ">= 95", + "i1-2": "<= 0", + "o1-1": "'excellent'", + "o1-2": "30" + }, + { + "_id": "rule2", + "i1-1": ">= 90", + "i1-2": "<= 1", + "o1-1": "'good'", + "o1-2": "20" + }, + { + "_id": "rule3", + "i1-1": ">= 80", + "i1-2": "<= 2", + "o1-1": "'average'", + "o1-2": "0" + }, + { + "_id": "rule4", + "i1-1": ">= 70", + "i1-2": "<= 3", + "o1-1": "'below_average'", + "o1-2": "-10" + }, + { + "_id": "rule5", + "i1-1": "", + "i1-2": "", + "o1-1": "'poor'", + "o1-2": "-30" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "On-time Payment Percentage", + "field": "account.payment_history.on_time_payment_percentage" + }, + { + "id": "i1-2", + "name": "Late Payments (Last 12 Months)", + "field": "account.payment_history.late_payments_last_12_months" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Payment History Rating", + "field": "evaluation.payment_history_rating" + }, + { + "id": "o1-2", + "name": "Payment History Score", + "field": "evaluation.payment_history_score" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "paymentHistoryNode", + "name": "payment_history_evaluation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i2-1": "< 30", + "i2-2": "< 50", + "o2-1": "'low'", + "o2-2": "25" + }, + { + "_id": "rule2", + "i2-1": ">= 30, < 50", + "i2-2": ">= 50, < 70", + "o2-1": "'moderate'", + "o2-2": "15" + }, + { + "_id": "rule3", + "i2-1": ">= 50, < 70", + "i2-2": ">= 70, < 85", + "o2-1": "'high'", + "o2-2": "0" + }, + { + "_id": "rule4", + "i2-1": ">= 70, < 85", + "i2-2": ">= 85, < 95", + "o2-1": "'very_high'", + "o2-2": "-15" + }, + { + "_id": "rule5", + "i2-1": "", + "i2-2": "", + "o2-1": "'excessive'", + "o2-2": "-25" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Current Utilization Percentage", + "field": "account.utilization.current_percentage" + }, + { + "id": "i2-2", + "name": "Average Utilization (Last 6 Months)", + "field": "account.utilization.average_last_6_months" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Utilization Rating", + "field": "evaluation.utilization_rating" + }, + { + "id": "o2-2", + "name": "Utilization Score", + "field": "evaluation.utilization_score" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "utilizationNode", + "name": "utilization_evaluation", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i3-1": "< 1", + "i3-2": ">= 3", + "i3-3": "true", + "o3-1": "'excellent'", + "o3-2": "25" + }, + { + "_id": "rule2", + "i3-1": "< 2", + "i3-2": ">= 2", + "i3-3": "true", + "o3-1": "'good'", + "o3-2": "15" + }, + { + "_id": "rule3", + "i3-1": "< 3", + "i3-2": ">= 1", + "i3-3": "", + "o3-1": "'average'", + "o3-2": "5" + }, + { + "_id": "rule4", + "i3-1": "< 4", + "i3-2": "< 1", + "i3-3": "false", + "o3-1": "'below_average'", + "o3-2": "-10" + }, + { + "_id": "rule5", + "i3-1": "", + "i3-2": "", + "i3-3": "", + "o3-1": "'poor'", + "o3-2": "-20" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Credit Inquiries (Last 12 Months)", + "field": "account.financial_behavior.credit_inquiries_last_12_months" + }, + { + "id": "i3-2", + "name": "Years with Institution", + "field": "account.financial_behavior.years_with_institution" + }, + { + "id": "i3-3", + "name": "Income Verification", + "field": "account.financial_behavior.income_verified" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Financial Behavior Rating", + "field": "evaluation.financial_behavior_rating" + }, + { + "id": "o3-2", + "name": "Financial Behavior Score", + "field": "evaluation.financial_behavior_score" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "financialBehaviorNode", + "name": "financial_behavior_evaluation", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "total_adjustment_score", + "value": "evaluation.payment_history_score + evaluation.utilization_score + evaluation.financial_behavior_score" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "scoreCalculationNode", + "name": "calculate_total_score", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i4-1": "> 50", + "o4-1": "30", + "o4-2": "'Significant increase recommended based on excellent history and behavior.'" + }, + { + "_id": "rule2", + "i4-1": "> 40", + "o4-1": "25", + "o4-2": "'Strong increase recommended based on very good history and behavior.'" + }, + { + "_id": "rule3", + "i4-1": "> 30", + "o4-1": "20", + "o4-2": "'Moderate increase recommended based on good history and behavior.'" + }, + { + "_id": "rule4", + "i4-1": "> 20", + "o4-1": "15", + "o4-2": "'Increase recommended based on above average history and behavior.'" + }, + { + "_id": "rule5", + "i4-1": "> 10", + "o4-1": "10", + "o4-2": "'Small increase recommended based on satisfactory history and behavior.'" + }, + { + "_id": "rule6", + "i4-1": "> 0", + "o4-1": "5", + "o4-2": "'Minimal increase recommended based on acceptable history and behavior.'" + }, + { + "_id": "rule7", + "i4-1": "> -10", + "o4-1": "0", + "o4-2": "'No change recommended, monitoring advised.'" + }, + { + "_id": "rule8", + "i4-1": "> -20", + "o4-1": "-5", + "o4-2": "'Small decrease recommended due to concerning trends.'" + }, + { + "_id": "rule9", + "i4-1": "> -30", + "o4-1": "-10", + "o4-2": "'Moderate decrease recommended due to negative indicators.'" + }, + { + "_id": "rule10", + "i4-1": "> -40", + "o4-1": "-15", + "o4-2": "'Significant decrease recommended due to high risk factors.'" + }, + { + "_id": "rule11", + "i4-1": "", + "o4-1": "-20", + "o4-2": "'Major decrease recommended due to severe risk factors.'" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "Total Adjustment Score", + "field": "total_adjustment_score" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "Percent Change", + "field": "recommendation.percent_change" + }, + { + "id": "o4-2", + "name": "Justification", + "field": "recommendation.justification" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "creditLimitRecommendationNode", + "name": "credit_limit_recommendation", + "position": { + "x": 1710, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "recommendation.amount_change", + "value": "round(account.current_credit_limit * (recommendation.percent_change / 100))" + }, + { + "id": "expr2", + "key": "recommendation.new_credit_limit", + "value": "account.current_credit_limit + $.recommendation.amount_change" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "finalCalculationNode", + "name": "calculate_final_amounts", + "position": { + "x": 2030, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "inputNode", + "targetId": "paymentHistoryNode", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "paymentHistoryNode", + "targetId": "utilizationNode", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "utilizationNode", + "targetId": "financialBehaviorNode", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "financialBehaviorNode", + "targetId": "scoreCalculationNode", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "scoreCalculationNode", + "targetId": "creditLimitRecommendationNode", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "creditLimitRecommendationNode", + "targetId": "finalCalculationNode", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/customer-eligibility-engine.json b/test-data/graphs/customer-eligibility-engine.json new file mode 100644 index 00000000..f6646dd9 --- /dev/null +++ b/test-data/graphs/customer-eligibility-engine.json @@ -0,0 +1,551 @@ +{ + "tests": [ + { + "input": { + "customerId": "CUST12345", + "accountInfo": { + "accountAge": 28, + "paymentHistory": "excellent", + "currentPlan": "Family Premium 50GB", + "monthlySpend": 95, + "contractStatus": "pending_renewal" + }, + "usageStats": { + "dataUsageGB": 42.5, + "dataUtilizationPercent": 85, + "callMinutes": 350, + "textMessages": 1250 + }, + "customerProfile": { + "segment": "consumer", + "location": "Seattle, WA", + "devices": [ + "iPhone 14", + "iPad Air", + "Apple Watch" + ], + "previousComplaints": 0 + } + }, + "output": { + "features": { + "conciergeService": false, + "contentStreaming": true, + "internationalRoaming": true, + "message": "Most premium features available based on gold status.", + "prioritySupport": true + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"customerId\": {\n \"type\": \"string\",\n \"description\": \"Unique identifier for the customer\"\n },\n \"accountInfo\": {\n \"type\": \"object\",\n \"properties\": {\n \"accountAge\": {\n \"type\": \"number\",\n \"description\": \"Account age in months\"\n },\n \"paymentHistory\": {\n \"type\": \"string\",\n \"enum\": [\"excellent\", \"good\", \"fair\", \"poor\"],\n \"description\": \"Customer payment history classification\"\n },\n \"currentPlan\": {\n \"type\": \"string\",\n \"description\": \"Current service plan\"\n },\n \"monthlySpend\": {\n \"type\": \"number\",\n \"description\": \"Average monthly spend in dollars\"\n },\n \"contractStatus\": {\n \"type\": \"string\",\n \"enum\": [\"active\", \"pending_renewal\", \"ending_soon\", \"expired\"],\n \"description\": \"Current contract status\"\n }\n }\n },\n \"usageStats\": {\n \"type\": \"object\",\n \"properties\": {\n \"dataUsageGB\": {\n \"type\": \"number\",\n \"description\": \"Average monthly data usage in GB\"\n },\n \"dataUtilizationPercent\": {\n \"type\": \"number\",\n \"description\": \"Percentage of data allowance used\"\n },\n \"callMinutes\": {\n \"type\": \"number\",\n \"description\": \"Average monthly call minutes\"\n },\n \"textMessages\": {\n \"type\": \"number\",\n \"description\": \"Average monthly text messages sent\"\n }\n }\n },\n \"customerProfile\": {\n \"type\": \"object\",\n \"properties\": {\n \"segment\": {\n \"type\": \"string\",\n \"enum\": [\"consumer\", \"small_business\", \"enterprise\"],\n \"description\": \"Customer segment\"\n },\n \"location\": {\n \"type\": \"string\",\n \"description\": \"Customer geographic location\"\n },\n \"devices\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"List of devices on account\"\n },\n \"previousComplaints\": {\n \"type\": \"number\",\n \"description\": \"Number of previous complaints\"\n }\n }\n }\n }\n}" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": ">= 24", + "i2": "'excellent'", + "i3": "", + "o1": "\"excellent\"", + "o2": "true" + }, + { + "_id": "r2", + "i1": ">= 12", + "i2": "'excellent', 'good'", + "i3": "'active', 'pending_renewal'", + "o1": "\"good\"", + "o2": "true" + }, + { + "_id": "r3", + "i1": ">= 6", + "i2": "'excellent', 'good', 'fair'", + "i3": "'active', 'pending_renewal'", + "o1": "\"fair\"", + "o2": "true" + }, + { + "_id": "r4", + "i1": "< 6", + "i2": "'excellent', 'good'", + "i3": "'active'", + "o1": "\"fair\"", + "o2": "true" + }, + { + "_id": "r5", + "i1": "", + "i2": "'poort'", + "i3": "", + "o1": "\"poor\"", + "o2": "false" + }, + { + "_id": "r6", + "i1": "", + "i2": "", + "i3": "'expired'", + "o1": "\"poor\"", + "o2": "false" + }, + { + "_id": "r7", + "i1": "", + "i2": "", + "i3": "", + "o1": "\"review\"", + "o2": "false" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Account Age (Months)", + "field": "accountInfo.accountAge" + }, + { + "id": "i2", + "name": "Payment History", + "field": "accountInfo.paymentHistory" + }, + { + "id": "i3", + "name": "Contract Status", + "field": "accountInfo.contractStatus" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Account Status", + "field": "eligibility.accountStatus" + }, + { + "id": "o2", + "name": "In Good Standing", + "field": "eligibility.goodStanding" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "accountStatus", + "name": "evaluateAccountStatus", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": ">= 36", + "i2": ">= 120", + "i3": "'excellent'", + "o1": "\"platinum\"", + "o2": "20" + }, + { + "_id": "r2", + "i1": ">= 24", + "i2": ">= 80", + "i3": "'excellent', 'good'", + "o1": "\"gold\"", + "o2": "15" + }, + { + "_id": "r3", + "i1": ">= 12", + "i2": ">= 50", + "i3": "'excellent', 'good', 'fair'", + "o1": "\"silver\"", + "o2": "10" + }, + { + "_id": "r4", + "i1": ">= 6", + "i2": ">= 30", + "i3": "", + "o1": "\"bronze\"", + "o2": "5" + }, + { + "_id": "r5", + "i1": "", + "i2": "", + "i3": "", + "o1": "\"standard\"", + "o2": "0" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Account Age (Months)", + "field": "accountInfo.accountAge" + }, + { + "id": "i2", + "name": "Monthly Spend ($)", + "field": "accountInfo.monthlySpend" + }, + { + "id": "i3", + "name": "Account Status", + "field": "eligibility.accountStatus" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Loyalty Tier", + "field": "eligibility.loyaltyTier" + }, + { + "id": "o2", + "name": "Loyalty Discount", + "field": "eligibility.loyaltyDiscountPercent" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "loyaltyTier", + "name": "determineLoyaltyTier", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "true", + "i2": "['platinum', 'gold']", + "i3": "accountInfo.contractStatus == 'pending_renewal' or accountInfo.contractStatus == 'ending_soon'", + "o1": "true", + "o2": "true", + "o3": "true", + "o4": "\"High-priority upgrade eligible. Offers for all plan categories.\"" + }, + { + "_id": "r2", + "i1": "true", + "i2": "['platinum', 'gold']", + "i3": "", + "o1": "true", + "o2": "true", + "o3": "false", + "o4": "\"Premium plan upgrade eligible based on customer tier.\"" + }, + { + "_id": "r3", + "i1": "true", + "i2": "['silver']", + "i3": "accountInfo.contractStatus == 'pending_renewal' or accountInfo.contractStatus == 'ending_soon'", + "o1": "true", + "o2": "false", + "o3": "false", + "o4": "\"Standard upgrade eligible based on contract status.\"" + }, + { + "_id": "r4", + "i1": "true", + "i2": "['bronze', 'standard']", + "i3": "accountInfo.contractStatus == 'ending_soon'", + "o1": "true", + "o2": "false", + "o3": "false", + "o4": "\"Basic upgrade eligible as contract is ending.\"" + }, + { + "_id": "r5", + "i1": "false", + "i2": "", + "i3": "", + "o1": "false", + "o2": "false", + "o3": "false", + "o4": "\"Not eligible for upgrades due to account standing.\"" + }, + { + "_id": "r6", + "i1": "", + "i2": "", + "i3": "", + "o1": "false", + "o2": "false", + "o3": "false", + "o4": "\"Standard eligibility rules apply.\"" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Good Standing", + "field": "eligibility.goodStanding" + }, + { + "id": "i2", + "name": "Loyalty Tier", + "field": "eligibility.loyaltyTier" + }, + { + "id": "i3", + "name": "Contract Condition" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Eligible For Upgrade", + "field": "eligibility.canUpgrade" + }, + { + "id": "o2", + "name": "Premium Plan Eligible", + "field": "eligibility.premiumPlanEligible" + }, + { + "id": "o3", + "name": "Early Upgrade Eligible", + "field": "eligibility.earlyUpgradeEligible" + }, + { + "id": "o4", + "name": "Upgrade Message", + "field": "eligibility.upgradeMessage" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "upgradeEligibility", + "name": "determineUpgradeEligibility", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "eligibility.specialOffers", + "value": "{\n \"internationalBundle\": usageStats.callMinutes > 300,\n \"dataBooster\": usageStats.dataUtilizationPercent > 80,\n \"familyPlan\": len(customerProfile.devices) >= 3,\n \"deviceUpgrade\": eligibility.canUpgrade,\n \"loyaltyReward\": eligibility.loyaltyTier in [\"platinum\", \"gold\", \"silver\"]\n}" + }, + { + "id": "e2", + "key": "eligibility.offerCount", + "value": "len(filter(values($.eligibility.specialOffers), # == true))" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "specialOffers", + "name": "determineSpecialOffers", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "['platinum']", + "i2": "true", + "i3": ">= 3", + "o1": "true", + "o2": "true", + "o3": "true", + "o4": "true", + "o5": "\"All premium features available based on platinum status.\"" + }, + { + "_id": "r2", + "i1": "['gold']", + "i2": "true", + "i3": ">= 2", + "o1": "true", + "o2": "true", + "o3": "true", + "o4": "false", + "o5": "\"Most premium features available based on gold status.\"" + }, + { + "_id": "r3", + "i1": "['silver']", + "i2": "true", + "i3": ">= 1", + "o1": "true", + "o2": "true", + "o3": "false", + "o4": "false", + "o5": "\"Selected premium features available based on silver status.\"" + }, + { + "_id": "r4", + "i1": "['bronze']", + "i2": "true", + "i3": "", + "o1": "true", + "o2": "false", + "o3": "false", + "o4": "false", + "o5": "\"Basic premium features available based on bronze status.\"" + }, + { + "_id": "r5", + "i1": "", + "i2": "false", + "i3": "", + "o1": "false", + "o2": "false", + "o3": "false", + "o4": "false", + "o5": "\"No premium features available due to account standing.\"" + }, + { + "_id": "r6", + "i1": "", + "i2": "", + "i3": "", + "o1": "false", + "o2": "false", + "o3": "false", + "o4": "false", + "o5": "\"No premium features available.\"" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Loyalty Tier", + "field": "eligibility.loyaltyTier" + }, + { + "id": "i2", + "name": "Good Standing", + "field": "eligibility.goodStanding" + }, + { + "id": "i3", + "name": "Special Offer Count", + "field": "eligibility.offerCount" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Priority Support", + "field": "features.prioritySupport" + }, + { + "id": "o2", + "name": "Content Streaming", + "field": "features.contentStreaming" + }, + { + "id": "o3", + "name": "International Roaming", + "field": "features.internationalRoaming" + }, + { + "id": "o4", + "name": "Concierge Service", + "field": "features.conciergeService" + }, + { + "id": "o5", + "name": "Features Message", + "field": "features.message" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "premiumFeatures", + "name": "determinePremiumFeatures", + "position": { + "x": 1710, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "accountStatus", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "accountStatus", + "targetId": "loyaltyTier", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "loyaltyTier", + "targetId": "upgradeEligibility", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "upgradeEligibility", + "targetId": "specialOffers", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "specialOffers", + "targetId": "premiumFeatures", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/customer-lifetime-value.json b/test-data/graphs/customer-lifetime-value.json new file mode 100644 index 00000000..2e0df62d --- /dev/null +++ b/test-data/graphs/customer-lifetime-value.json @@ -0,0 +1,200 @@ +{ + "tests": [ + { + "input": { + "customer": { + "id": "CUST-12345", + "name": "John Doe", + "segment": "retail", + "acquisitionCost": 150, + "acquisitionChannel": "paid_search" + }, + "purchaseHistory": { + "orderValues": [ + 120, + 89, + 245, + 78, + 310 + ], + "customerDurationMonths": 18, + "averageGrossMarginPercent": 35, + "retentionRate": 85 + } + }, + "output": { + "acquisitionCostRatio": 0.009543603664743808, + "adjustedLTV": 15567.333333333334, + "averageOrderValue": 168.4, + "basicLTV": 15717.333333333334, + "customer": { + "acquisitionChannel": "paid_search", + "acquisitionCost": 150, + "id": "CUST-12345", + "name": "John Doe", + "segment": "retail" + }, + "customerInsights": { + "recommendedStrategy": "High-touch service, premium offers, exclusive events", + "tier": "platinum" + }, + "customerLifetimeMonths": 80, + "grossMargin": 0.35, + "purchaseFrequency": 3.3333333333333335, + "purchaseHistory": { + "averageGrossMarginPercent": 35, + "customerDurationMonths": 18, + "orderValues": [ + 120, + 89, + 245, + 78, + 310 + ], + "retentionRate": 85 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "averageOrderValue", + "value": "sum(purchaseHistory.orderValues) / len(purchaseHistory.orderValues)" + }, + { + "id": "e1-2", + "key": "purchaseFrequency", + "value": "len(purchaseHistory.orderValues) / purchaseHistory.customerDurationMonths * 12" + }, + { + "id": "e1-3", + "key": "grossMargin", + "value": "purchaseHistory.averageGrossMarginPercent / 100" + }, + { + "id": "e1-4", + "key": "customerLifetimeMonths", + "value": "1 / (1 - purchaseHistory.retentionRate / 100) * 12" + }, + { + "id": "e1-5", + "key": "basicLTV", + "value": "$.averageOrderValue * $.purchaseFrequency * $.grossMargin * $.customerLifetimeMonths" + }, + { + "id": "e1-6", + "key": "acquisitionCostRatio", + "value": "customer.acquisitionCost / $.basicLTV" + }, + { + "id": "e1-7", + "key": "adjustedLTV", + "value": "$.basicLTV - customer.acquisitionCost" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "clv_calculation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "> 2000", + "o1-1": "'platinum'", + "o1-2": "'High-touch service, premium offers, exclusive events'" + }, + { + "_id": "r1-2", + "i1-1": "> 1000", + "o1-1": "'gold'", + "o1-2": "'Priority service, personalized offers, loyalty bonuses'" + }, + { + "_id": "r1-3", + "i1-1": "> 500", + "o1-1": "'silver'", + "o1-2": "'Enhanced service, targeted offers, occasional perks'" + }, + { + "_id": "r1-4", + "i1-1": "", + "o1-1": "'standard'", + "o1-2": "'Standard service, general promotions'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Adjusted LTV", + "field": "adjustedLTV" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Customer Tier", + "field": "customerInsights.tier" + }, + { + "id": "o1-2", + "name": "Recommended Strategy", + "field": "customerInsights.recommendedStrategy" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "customer_segmentation", + "position": { + "x": 750, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ex1", + "targetId": "dt1", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/customer-onboarding-kyc-verification.json b/test-data/graphs/customer-onboarding-kyc-verification.json new file mode 100644 index 00000000..880d58b8 --- /dev/null +++ b/test-data/graphs/customer-onboarding-kyc-verification.json @@ -0,0 +1,611 @@ +{ + "tests": [ + { + "input": { + "customer": { + "id": "CUST12345", + "firstName": "John", + "lastName": "Smith", + "dateOfBirth": "1985-06-15", + "email": "john.smith@example.com", + "phone": "+1-555-123-4567", + "address": { + "line1": "123 Main Street", + "line2": "Apt 4B", + "city": "New York", + "state": "NY", + "postalCode": "10001", + "country": "US" + }, + "isPoliticallyExposed": false, + "isHighRiskBusiness": false, + "occupation": "Software Engineer", + "employerName": "Tech Company Inc." + }, + "financialInfo": { + "estimatedTransactionValue": 25000, + "accountPurpose": "Savings and Investment", + "sourceOfFunds": "Employment Income" + }, + "verification": { + "documentType": "passport", + "documentStatus": "valid", + "documentNumber": "P123456789", + "documentExpiry": "2028-05-20", + "documentIssuingCountry": "US" + }, + "watchlist": { + "sanctionsMatch": false, + "pepListMatch": false, + "adverseMediaMatch": false + } + }, + "output": { + "nextSteps": "Onboarding approved", + "requiredActionsCount": 0, + "requirements": { + "addressVerification": false, + "enhancedMonitoring": false, + "faceVerification": false, + "sourceOfFunds": false + }, + "verificationStatus": "approved" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "risk1", + "country": "'US', 'CA', 'GB', 'AU', 'NZ', 'JP', 'DE', 'FR'", + "pep": "false", + "highRiskBusiness": "false", + "transactionValue": "< 10000", + "o1": "10", + "o2": "'low'" + }, + { + "_id": "risk2", + "country": "'US', 'CA', 'GB', 'AU', 'NZ', 'JP', 'DE', 'FR'", + "pep": "false", + "highRiskBusiness": "false", + "transactionValue": ">= 10000, < 100000", + "o1": "30", + "o2": "'medium'" + }, + { + "_id": "risk3", + "country": "'US', 'CA', 'GB', 'AU', 'NZ', 'JP', 'DE', 'FR'", + "pep": "true", + "highRiskBusiness": "", + "transactionValue": "", + "o1": "75", + "o2": "'high'" + }, + { + "_id": "risk4", + "country": "'US', 'CA', 'GB', 'AU', 'NZ', 'JP', 'DE', 'FR'", + "pep": "", + "highRiskBusiness": "true", + "transactionValue": "", + "o1": "70", + "o2": "'high'" + }, + { + "_id": "risk5", + "country": "'RU', 'IR', 'KP', 'CU', 'SY', 'VE'", + "pep": "", + "highRiskBusiness": "", + "transactionValue": "", + "o1": "100", + "o2": "'very-high'" + }, + { + "_id": "risk6", + "country": "", + "pep": "true", + "highRiskBusiness": "true", + "transactionValue": "", + "o1": "90", + "o2": "'very-high'" + }, + { + "_id": "risk7", + "country": "", + "pep": "", + "highRiskBusiness": "", + "transactionValue": ">= 100000", + "o1": "60", + "o2": "'high'" + }, + { + "_id": "risk8", + "country": "", + "pep": "", + "highRiskBusiness": "", + "transactionValue": "", + "o1": "40", + "o2": "'medium'" + } + ], + "inputs": [ + { + "id": "country", + "name": "Country", + "field": "customer.address.country" + }, + { + "id": "pep", + "name": "PEP Status", + "field": "customer.isPoliticallyExposed" + }, + { + "id": "highRiskBusiness", + "name": "High Risk Business", + "field": "customer.isHighRiskBusiness" + }, + { + "id": "transactionValue", + "name": "Transaction Value", + "field": "financialInfo.estimatedTransactionValue" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Risk Score", + "field": "assessment.riskScore" + }, + { + "id": "o2", + "name": "Risk Level", + "field": "assessment.riskLevel" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "customerRiskScoring", + "name": "customerRiskScoring", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "doc1", + "i1": "'passport'", + "i2": "'valid'", + "i3": "'low', 'medium'", + "o1": "true", + "o2": "'standard'", + "o3": "false" + }, + { + "_id": "doc2", + "i1": "'passport'", + "i2": "'valid'", + "i3": "'high', 'very-high'", + "o1": "true", + "o2": "'enhanced'", + "o3": "true" + }, + { + "_id": "doc3", + "i1": "'driving_license'", + "i2": "'valid'", + "i3": "'low'", + "o1": "true", + "o2": "'standard'", + "o3": "false" + }, + { + "_id": "doc4", + "i1": "'driving_license'", + "i2": "'valid'", + "i3": "'medium', 'high', 'very-high'", + "o1": "false", + "o2": "'insufficient'", + "o3": "true" + }, + { + "_id": "doc5", + "i1": "'national_id'", + "i2": "'valid'", + "i3": "'low', 'medium'", + "o1": "true", + "o2": "'standard'", + "o3": "false" + }, + { + "_id": "doc6", + "i1": "'national_id'", + "i2": "'valid'", + "i3": "'high', 'very-high'", + "o1": "false", + "o2": "'insufficient'", + "o3": "true" + }, + { + "_id": "doc7", + "i1": "", + "i2": "'expired', 'damaged', 'suspicious'", + "i3": "", + "o1": "false", + "o2": "'rejected'", + "o3": "true" + }, + { + "_id": "doc8", + "i1": "", + "i2": "", + "i3": "", + "o1": "false", + "o2": "'missing'", + "o3": "true" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Document Type", + "field": "verification.documentType" + }, + { + "id": "i2", + "name": "Document Status", + "field": "verification.documentStatus" + }, + { + "id": "i3", + "name": "Risk Level", + "field": "assessment.riskLevel" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Document Verified", + "field": "verification.isDocumentVerified" + }, + { + "id": "o2", + "name": "Verification Status", + "field": "verification.documentVerificationStatus" + }, + { + "id": "o3", + "name": "Additional Verification Required", + "field": "verification.requiresAdditionalVerification" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "documentVerification", + "name": "documentVerification", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "watch1", + "i1": "true", + "i2": "", + "i3": "", + "o1": "false", + "o2": "'reject'", + "o3": "'Customer appears on sanctions list'" + }, + { + "_id": "watch2", + "i1": "false", + "i2": "true", + "i3": "", + "o1": "true", + "o2": "'review'", + "o3": "'Customer appears on PEP list - requires manual review'" + }, + { + "_id": "watch3", + "i1": "false", + "i2": "false", + "i3": "true", + "o1": "true", + "o2": "'review'", + "o3": "'Customer has adverse media - requires manual review'" + }, + { + "_id": "watch4", + "i1": "false", + "i2": "false", + "i3": "false", + "o1": "true", + "o2": "'pass'", + "o3": "'No watchlist hits found'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Sanctions Match", + "field": "watchlist.sanctionsMatch" + }, + { + "id": "i2", + "name": "PEP Match", + "field": "watchlist.pepListMatch" + }, + { + "id": "i3", + "name": "Adverse Media", + "field": "watchlist.adverseMediaMatch" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Watchlist Passed", + "field": "watchlist.passed" + }, + { + "id": "o2", + "name": "Watchlist Status", + "field": "watchlist.status" + }, + { + "id": "o3", + "name": "Watchlist Message", + "field": "watchlist.message" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "watchlistCheck", + "name": "watchlistCheck", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "exp1", + "key": "requiresEDD", + "value": "assessment.riskLevel == 'high' or assessment.riskLevel == 'very-high' or watchlist.status == 'review'" + }, + { + "id": "exp2", + "key": "isSanctioned", + "value": "watchlist.status == 'reject'" + }, + { + "id": "exp3", + "key": "dueDiligenceLevel", + "value": "$.isSanctioned ? 'blocked' : ($.requiresEDD ? 'enhanced' : 'standard')" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dueDiligenceLevel", + "name": "dueDiligenceLevel", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "add1", + "i1": "'enhanced'", + "i2": ">= 60", + "o1": "true", + "o2": "true", + "o3": "true", + "o4": "true" + }, + { + "_id": "add2", + "i1": "'enhanced'", + "i2": "< 60", + "o1": "true", + "o2": "true", + "o3": "false", + "o4": "true" + }, + { + "_id": "add3", + "i1": "'standard'", + "i2": ">= 40", + "o1": "false", + "o2": "true", + "o3": "false", + "o4": "false" + }, + { + "_id": "add4", + "i1": "'standard'", + "i2": "< 40", + "o1": "false", + "o2": "false", + "o3": "false", + "o4": "false" + }, + { + "_id": "add5", + "i1": "'blocked'", + "i2": "", + "o1": "false", + "o2": "false", + "o3": "false", + "o4": "false" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Due Diligence Level", + "field": "dueDiligenceLevel" + }, + { + "id": "i2", + "name": "Risk Score", + "field": "assessment.riskScore" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Requires Source of Funds", + "field": "requirements.sourceOfFunds" + }, + { + "id": "o2", + "name": "Requires Address Verification", + "field": "requirements.addressVerification" + }, + { + "id": "o3", + "name": "Requires Face Verification", + "field": "requirements.faceVerification" + }, + { + "id": "o4", + "name": "Requires Enhanced Monitoring", + "field": "requirements.enhancedMonitoring" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "additionalChecks", + "name": "additionalChecks", + "position": { + "x": 1710, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "exp1", + "key": "verificationStatus", + "value": "dueDiligenceLevel == 'blocked' ? 'rejected' : (verification.isDocumentVerified and watchlist.passed ? 'approved' : 'pending')" + }, + { + "id": "exp2", + "key": "requiredActionsCount", + "value": "count(values(requirements), # == true)" + }, + { + "id": "exp3", + "key": "nextSteps", + "value": "dueDiligenceLevel == 'blocked' ? 'Application rejected due to sanctions match' : ($.verificationStatus == 'pending' ? 'Additional verification required' : 'Onboarding approved')" + }, + { + "id": "exp4", + "key": "requirements", + "value": "requirements" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "verificationResult", + "name": "verificationResult", + "position": { + "x": 2030, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "customerRiskScoring", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "customerRiskScoring", + "targetId": "documentVerification", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "documentVerification", + "targetId": "watchlistCheck", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "watchlistCheck", + "targetId": "dueDiligenceLevel", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "dueDiligenceLevel", + "targetId": "additionalChecks", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "additionalChecks", + "targetId": "verificationResult", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/customer-service-escalation.json b/test-data/graphs/customer-service-escalation.json new file mode 100644 index 00000000..5e5e3447 --- /dev/null +++ b/test-data/graphs/customer-service-escalation.json @@ -0,0 +1,191 @@ +{ + "tests": [ + { + "input": { + "customer": { + "id": "C123456", + "name": "Acme Corporation", + "tier": "premium", + "accountAge": 36 + }, + "issue": { + "id": "ISS-789", + "type": "service_outage", + "complexity": "high", + "financialImpact": 7500, + "description": "Complete service outage affecting all production systems" + } + }, + "output": { + "escalation": { + "assignedTeam": "Executive Response Team", + "description": "Immediate executive team escalation required", + "level": "immediate_executive", + "priority": 1, + "slaMinutes": 30 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'premium'", + "i1-2": "'high'", + "i1-3": "> 5000", + "o1-1": "'immediate_executive'", + "o1-2": "'Immediate executive team escalation required'", + "o1-3": "1", + "o1-4": "30", + "o1-5": "'Executive Response Team'" + }, + { + "_id": "r1-2", + "i1-1": "'premium'", + "i1-2": "'high'", + "i1-3": "<= 5000", + "o1-1": "'senior_support'", + "o1-2": "'Escalate to senior support team'", + "o1-3": "2", + "o1-4": "120", + "o1-5": "'Senior Support Team'" + }, + { + "_id": "r1-3", + "i1-1": "'premium'", + "i1-2": "'medium', 'low'", + "i1-3": "> 1000", + "o1-1": "'senior_support'", + "o1-2": "'Escalate to senior support team'", + "o1-3": "2", + "o1-4": "120", + "o1-5": "'Senior Support Team'" + }, + { + "_id": "r1-4", + "i1-1": "'standard'", + "i1-2": "'high'", + "i1-3": "> 2000", + "o1-1": "'senior_support'", + "o1-2": "'Escalate to senior support team'", + "o1-3": "2", + "o1-4": "180", + "o1-5": "'Senior Support Team'" + }, + { + "_id": "r1-5", + "i1-1": "'standard'", + "i1-2": "'medium'", + "i1-3": "> 5000", + "o1-1": "'senior_support'", + "o1-2": "'Escalate to senior support team'", + "o1-3": "2", + "o1-4": "180", + "o1-5": "'Senior Support Team'" + }, + { + "_id": "r1-6", + "i1-1": "'trial'", + "i1-2": "'high'", + "i1-3": "> 5000", + "o1-1": "'senior_support'", + "o1-2": "'Escalate to senior support team'", + "o1-3": "3", + "o1-4": "240", + "o1-5": "'Senior Support Team'" + }, + { + "_id": "r1-7", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "o1-1": "'standard_support'", + "o1-2": "'Handle through standard support process'", + "o1-3": "4", + "o1-4": "480", + "o1-5": "'Standard Support Team'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Customer Tier", + "field": "customer.tier" + }, + { + "id": "i1-2", + "name": "Issue Complexity", + "field": "issue.complexity" + }, + { + "id": "i1-3", + "name": "Financial Impact", + "field": "issue.financialImpact" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Escalation Level", + "field": "escalation.level" + }, + { + "id": "o1-2", + "name": "Action Description", + "field": "escalation.description" + }, + { + "id": "o1-3", + "name": "Priority", + "field": "escalation.priority" + }, + { + "id": "o1-4", + "name": "SLA Minutes", + "field": "escalation.slaMinutes" + }, + { + "id": "o1-5", + "name": "Assigned Team", + "field": "escalation.assignedTeam" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "determine_escalation_level", + "position": { + "x": 430, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/delivery-route-optimizer.json b/test-data/graphs/delivery-route-optimizer.json new file mode 100644 index 00000000..13537000 --- /dev/null +++ b/test-data/graphs/delivery-route-optimizer.json @@ -0,0 +1,271 @@ +{ + "tests": [ + { + "input": { + "route": { + "id": "R1234", + "name": "Downtown Loop", + "capacityUtilization": 0.85, + "trafficCongestionMinutes": 12, + "deliveryWindowMinutes": 45, + "distanceKm": 8.5, + "otherCondition": "normal" + } + }, + "output": { + "distanceScore": 30, + "route": { + "capacityUtilization": 0.85, + "deliveryWindowMinutes": 45, + "distanceKm": 8.5, + "id": "R1234", + "name": "Downtown Loop", + "otherCondition": "normal", + "trafficCongestionMinutes": 12 + }, + "routeResult": { + "classification": "recommended", + "isApproved": true, + "message": "Route is recommended with good score." + }, + "routeScores": { + "baseScore": 100, + "priority": "high" + }, + "timeWindowScore": 30, + "totalScore": 160 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "> 0.8", + "i1-2": "< 15", + "i1-3": "", + "o1-1": "100", + "o1-2": "'high'" + }, + { + "_id": "r1-2", + "i1-1": "> 0.8", + "i1-2": "> 15", + "i1-3": "", + "o1-1": "80", + "o1-2": "'medium'" + }, + { + "_id": "r1-3", + "i1-1": "> 0.5", + "i1-2": "< 20", + "i1-3": "", + "o1-1": "70", + "o1-2": "'medium'" + }, + { + "_id": "r1-4", + "i1-1": "> 0.5", + "i1-2": "> 20", + "i1-3": "", + "o1-1": "60", + "o1-2": "'low'" + }, + { + "_id": "r1-5", + "i1-1": "< 0.5", + "i1-2": "< 30", + "i1-3": "", + "o1-1": "50", + "o1-2": "'low'" + }, + { + "_id": "r1-6", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "o1-1": "30", + "o1-2": "'very_low'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Capacity Utilization", + "field": "route.capacityUtilization" + }, + { + "id": "i1-2", + "name": "Traffic Congestion (min)", + "field": "route.trafficCongestionMinutes" + }, + { + "id": "i1-3", + "name": "Other Condition", + "field": "route.otherCondition" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Base Score", + "field": "routeScores.baseScore" + }, + { + "id": "o1-2", + "name": "Priority", + "field": "routeScores.priority" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "evaluate_base_score", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "timeWindowScore", + "value": "route.deliveryWindowMinutes <= 30 ? 50 : (route.deliveryWindowMinutes <= 60 ? 30 : 10)" + }, + { + "id": "e1-2", + "key": "distanceScore", + "value": "route.distanceKm <= 5 ? 40 : (route.distanceKm <= 10 ? 30 : (route.distanceKm <= 20 ? 20 : 10))" + }, + { + "id": "e1-3", + "key": "totalScore", + "value": "routeScores.baseScore + $.timeWindowScore + $.distanceScore" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculate_additional_scores", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "> 160", + "o2-1": "'optimal'", + "o2-2": "true", + "o2-3": "'Route is optimal with high score.'" + }, + { + "_id": "r2-2", + "i2-1": "> 120", + "o2-1": "'recommended'", + "o2-2": "true", + "o2-3": "'Route is recommended with good score.'" + }, + { + "_id": "r2-3", + "i2-1": "> 90", + "o2-1": "'acceptable'", + "o2-2": "true", + "o2-3": "'Route is acceptable with moderate score.'" + }, + { + "_id": "r2-4", + "i2-1": "", + "o2-1": "'not_recommended'", + "o2-2": "false", + "o2-3": "'Route is not recommended due to low score.'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Total Score", + "field": "totalScore" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Route Classification", + "field": "routeResult.classification" + }, + { + "id": "o2-2", + "name": "Is Approved", + "field": "routeResult.isApproved" + }, + { + "id": "o2-3", + "name": "Message", + "field": "routeResult.message" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "determine_route_approval", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ex1", + "targetId": "dt2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/device-compatibility-checker.json b/test-data/graphs/device-compatibility-checker.json new file mode 100644 index 00000000..81958802 --- /dev/null +++ b/test-data/graphs/device-compatibility-checker.json @@ -0,0 +1,303 @@ +{ + "tests": [ + { + "input": { + "deviceModel": "iPhone 13 Pro", + "deviceFirmware": "14.2.1", + "deviceId": "A1B2C3D4E5F6", + "subscriberId": "2022050789", + "requestTimestamp": "2023-04-15T10:30:45Z" + }, + "output": { + "compatibility": { + "advancedFeatures": true, + "basicService": true, + "hdStreaming": false, + "nextGenFeatures": false + }, + "deviceFirmware": "14.2.1", + "deviceId": "A1B2C3D4E5F6", + "deviceModel": "iPhone 13 Pro", + "majorVersion": 14, + "normalizedModel": "iphone 13 pro", + "requestTimestamp": "2023-04-15T10:30:45Z", + "subscriberId": "2022050789" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "normalizedModel", + "value": "lower(deviceModel)" + }, + { + "id": "e1-3", + "key": "majorVersion", + "value": "number(split(deviceFirmware, '.')[0])" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "normalize_data", + "position": { + "x": 430, + "y": 115 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "contains($, 'iphone')", + "i1-2": ">= 15", + "o1-1": "true", + "o1-2": "true", + "o1-3": "true", + "o1-4": "true" + }, + { + "_id": "r1-2", + "i1-1": "contains($, 'iphone')", + "i1-2": ">= 13 and < 15", + "o1-1": "true", + "o1-2": "true", + "o1-3": "true", + "o1-4": "false" + }, + { + "_id": "r1-3", + "i1-1": "contains($, 'iphone')", + "i1-2": ">= 10 and < 13", + "o1-1": "true", + "o1-2": "true", + "o1-3": "false", + "o1-4": "false" + }, + { + "_id": "r1-4", + "i1-1": "contains($, 'iphone')", + "i1-2": "< 10", + "o1-1": "true", + "o1-2": "false", + "o1-3": "false", + "o1-4": "false" + }, + { + "_id": "r1-5", + "i1-1": "contains($, 'samsung galaxy')", + "i1-2": ">= 10", + "o1-1": "true", + "o1-2": "true", + "o1-3": "true", + "o1-4": "false" + }, + { + "_id": "r1-6", + "i1-1": "contains($, 'samsung galaxy')", + "i1-2": ">= 8 and < 10", + "o1-1": "true", + "o1-2": "true", + "o1-3": "false", + "o1-4": "false" + }, + { + "_id": "r1-7", + "i1-1": "contains($, 'samsung galaxy')", + "i1-2": "< 8", + "o1-1": "true", + "o1-2": "false", + "o1-3": "false", + "o1-4": "false" + }, + { + "_id": "r1-8", + "i1-1": "contains($, 'pixel')", + "i1-2": ">= 6", + "o1-1": "true", + "o1-2": "true", + "o1-3": "true", + "o1-4": "false" + }, + { + "_id": "r1-9", + "i1-1": "contains($, 'pixel')", + "i1-2": ">= 4 and < 6", + "o1-1": "true", + "o1-2": "true", + "o1-3": "false", + "o1-4": "false" + }, + { + "_id": "r1-10", + "i1-1": "contains($, 'pixel')", + "i1-2": "< 4", + "o1-1": "true", + "o1-2": "false", + "o1-3": "false", + "o1-4": "false" + }, + { + "_id": "r1-11", + "i1-1": "", + "i1-2": "", + "o1-1": "false", + "o1-2": "false", + "o1-3": "false", + "o1-4": "false" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Device Model", + "field": "normalizedModel" + }, + { + "id": "i1-2", + "name": "Major Version", + "field": "majorVersion" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Basic Service", + "field": "compatibility.basicService" + }, + { + "id": "o1-2", + "name": "HD Streaming", + "field": "compatibility.hdStreaming" + }, + { + "id": "o1-3", + "name": "Advanced Features", + "field": "compatibility.advancedFeatures" + }, + { + "id": "o1-4", + "name": "Next Gen Features", + "field": "compatibility.nextGenFeatures" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt1", + "name": "determine_compatibility", + "position": { + "x": 750, + "y": 115 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "contains($, 'iphone')", + "624d983d-f416-4f68-b194-750f45445670": "<= 14", + "o2-1": "false" + }, + { + "_id": "r2-2", + "i2-1": "contains($, 'samsung galaxy')", + "624d983d-f416-4f68-b194-750f45445670": "", + "o2-1": "false" + }, + { + "_id": "r2-3", + "i2-1": "contains($, 'pixel')", + "624d983d-f416-4f68-b194-750f45445670": "", + "o2-1": "false" + }, + { + "_id": "r2-4", + "i2-1": "", + "624d983d-f416-4f68-b194-750f45445670": "", + "o2-1": "compatibility.hdStreaming" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Device Model", + "field": "normalizedModel" + }, + { + "id": "624d983d-f416-4f68-b194-750f45445670", + "field": "majorVersion", + "name": "Major version" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "HD Streaming Final", + "field": "compatibility.hdStreaming" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt2", + "name": "check_minor_version", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ex1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt1", + "targetId": "dt2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/disaster-relief-fund-allocation.json b/test-data/graphs/disaster-relief-fund-allocation.json new file mode 100644 index 00000000..43ed88ee --- /dev/null +++ b/test-data/graphs/disaster-relief-fund-allocation.json @@ -0,0 +1,296 @@ +{ + "tests": [ + { + "input": { + "assessment": { + "damageLevel": "major", + "propertyType": "residential", + "damageDescription": "Roof collapsed in multiple areas, extensive water damage" + }, + "household": { + "size": 4, + "dependents": 2, + "specialNeeds": false + }, + "income": { + "level": "low", + "annualAmount": 32000, + "primarySource": "employment" + }, + "insurance": { + "status": "partial", + "deductible": 5000, + "provider": "StateInsurance" + } + }, + "output": { + "assessment": { + "damageDescription": "Roof collapsed in multiple areas, extensive water damage", + "damageLevel": "major", + "propertyType": "residential" + }, + "household": { + "dependents": 2, + "size": 4, + "specialNeeds": false + }, + "householdMultiplier": 1.6, + "income": { + "annualAmount": 32000, + "level": "low", + "primarySource": "employment" + }, + "initialAllocation": 14400, + "insurance": { + "deductible": 5000, + "provider": "StateInsurance", + "status": "partial" + }, + "relief": { + "baseAmount": 7500, + "incomeAdjustedAmount": 9000, + "paymentAmount": 10080, + "paymentReason": "Partially insured - reduced payment" + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'severe'", + "o1-1": "10000" + }, + { + "_id": "r1-2", + "i1-1": "'major'", + "o1-1": "7500" + }, + { + "_id": "r1-3", + "i1-1": "'moderate'", + "o1-1": "5000" + }, + { + "_id": "r1-4", + "i1-1": "'minor'", + "o1-1": "2500" + }, + { + "_id": "r1-5", + "i1-1": "", + "o1-1": "1000" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Damage Level", + "field": "assessment.damageLevel" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Base Amount", + "field": "relief.baseAmount" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "baseFundAllocation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "'low'", + "o3-1": "relief.baseAmount * 1.2" + }, + { + "_id": "r3-2", + "i3-1": "'medium'", + "o3-1": "relief.baseAmount" + }, + { + "_id": "r3-3", + "i3-1": "'high'", + "o3-1": "relief.baseAmount * 0.8" + }, + { + "_id": "r3-4", + "i3-1": "", + "o3-1": "relief.baseAmount" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Income Level", + "field": "income.level" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Income Adjusted Amount", + "field": "relief.incomeAdjustedAmount" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt3", + "name": "incomeAdjustment", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "householdMultiplier", + "value": "min([household.size * 0.15 + 1, 1.75])" + }, + { + "id": "e1-2", + "key": "initialAllocation", + "value": "relief.incomeAdjustedAmount * $.householdMultiplier" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "householdSizeAdjustment", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'none'", + "o2-1": "initialAllocation", + "o2-2": "'Not insured - full payment'" + }, + { + "_id": "r2-2", + "i2-1": "'partial'", + "o2-1": "max([initialAllocation * 0.7, 1000])", + "o2-2": "'Partially insured - reduced payment'" + }, + { + "_id": "r2-3", + "i2-1": "'full'", + "o2-1": "max([initialAllocation * 0.3, 500])", + "o2-2": "'Fully insured - minimal supplemental payment'" + }, + { + "_id": "r2-4", + "i2-1": "", + "o2-1": "initialAllocation * 0.5", + "o2-2": "'Unknown insurance status - standard reduction'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Insurance Status", + "field": "insurance.status" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Final Payment", + "field": "relief.paymentAmount" + }, + { + "id": "o2-2", + "name": "Reason", + "field": "relief.paymentReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt2", + "name": "insuranceAdjustment", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "dt3", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt3", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "ex1", + "targetId": "dt2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/dynamic-fx-rate-pricing-system.json b/test-data/graphs/dynamic-fx-rate-pricing-system.json new file mode 100644 index 00000000..f812a7cb --- /dev/null +++ b/test-data/graphs/dynamic-fx-rate-pricing-system.json @@ -0,0 +1,237 @@ +{ + "tests": [ + { + "input": { + "product": { + "id": "PRD-12345", + "name": "Luxury Watch", + "basePrice": 8500 + }, + "baseCurrency": "USD", + "targetCurrency": "EUR", + "quantity": 1, + "customerTier": "gold" + }, + "output": { + "fxDetails": { + "discount": 0.015, + "message": "Luxury products receive favorable rates", + "rate": 0.91 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "inputNode", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1-1": ">= 10000", + "o1-1": "'premium'" + }, + { + "_id": "rule2", + "i1-1": ">= 5000", + "o1-1": "'luxury'" + }, + { + "_id": "rule3", + "i1-1": ">= 1000", + "o1-1": "'mid-range'" + }, + { + "_id": "rule4", + "i1-1": "", + "o1-1": "'standard'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Product Price", + "field": "product.basePrice" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Product Category", + "field": "product.category" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "productCategoryDT", + "name": "determineProductCategory", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i2-1": "'premium'", + "i2-2": "'USD'", + "i2-3": "'EUR'", + "o2-1": "0.90", + "o2-2": "0.02", + "o2-3": "'Premium products receive our most favorable rate'" + }, + { + "_id": "rule2", + "i2-1": "'premium'", + "i2-2": "'USD'", + "i2-3": "'GBP'", + "o2-1": "0.78", + "o2-2": "0.02", + "o2-3": "'Premium products receive our most favorable rate'" + }, + { + "_id": "rule3", + "i2-1": "'luxury'", + "i2-2": "'USD'", + "i2-3": "'EUR'", + "o2-1": "0.91", + "o2-2": "0.015", + "o2-3": "'Luxury products receive favorable rates'" + }, + { + "_id": "rule4", + "i2-1": "'luxury'", + "i2-2": "'USD'", + "i2-3": "'GBP'", + "o2-1": "0.79", + "o2-2": "0.015", + "o2-3": "'Luxury products receive favorable rates'" + }, + { + "_id": "rule5", + "i2-1": "'mid-range'", + "i2-2": "'USD'", + "i2-3": "'EUR'", + "o2-1": "0.92", + "o2-2": "0.01", + "o2-3": "'Mid-range products receive standard rates'" + }, + { + "_id": "rule6", + "i2-1": "'mid-range'", + "i2-2": "'USD'", + "i2-3": "'GBP'", + "o2-1": "0.80", + "o2-2": "0.01", + "o2-3": "'Mid-range products receive standard rates'" + }, + { + "_id": "rule7", + "i2-1": "'standard'", + "i2-2": "'USD'", + "i2-3": "'EUR'", + "o2-1": "0.93", + "o2-2": "0", + "o2-3": "'Standard products receive base rates'" + }, + { + "_id": "rule8", + "i2-1": "'standard'", + "i2-2": "'USD'", + "i2-3": "'GBP'", + "o2-1": "0.81", + "o2-2": "0", + "o2-3": "'Standard products receive base rates'" + }, + { + "_id": "rule9", + "i2-1": "", + "i2-2": "", + "i2-3": "", + "o2-1": "1.0", + "o2-2": "0", + "o2-3": "'Default base rate applied'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Category", + "field": "product.category" + }, + { + "id": "i2-2", + "name": "Base Currency", + "field": "baseCurrency" + }, + { + "id": "i2-3", + "name": "Target Currency", + "field": "targetCurrency" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "FX Rate", + "field": "fxDetails.rate" + }, + { + "id": "o2-2", + "name": "Discount", + "field": "fxDetails.discount" + }, + { + "id": "o2-3", + "name": "Message", + "field": "fxDetails.message" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "fxRateAdjustmentDT", + "name": "determineFXRateAdjustment", + "position": { + "x": 750, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "inputNode", + "targetId": "productCategoryDT", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "productCategoryDT", + "targetId": "fxRateAdjustmentDT", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/dynamic-marketplace-comission-calculator.json b/test-data/graphs/dynamic-marketplace-comission-calculator.json new file mode 100644 index 00000000..ec66a61b --- /dev/null +++ b/test-data/graphs/dynamic-marketplace-comission-calculator.json @@ -0,0 +1,242 @@ +{ + "tests": [ + { + "input": { + "product": { + "category": "electronics", + "id": "prod-123" + }, + "sales": { + "amount": 750, + "volume": 120 + }, + "seller": { + "id": "sell-456", + "rating": 4.7, + "fulfillmentRate": 97 + }, + "promotion": { + "startDate": "2025-02-01", + "endDate": "2025-04-01" + } + }, + "output": { + "finalCommissionRate": 0.168, + "isPromotionActive": false, + "promotionAdjustment": 0, + "volumeMultiplier": 1.2 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "'electronics'", + "i2": "> 500", + "o1": "0.12" + }, + { + "_id": "r2", + "i1": "'electronics'", + "i2": "", + "o1": "0.08" + }, + { + "_id": "r3", + "i1": "'fashion'", + "i2": "> 300", + "o1": "0.15" + }, + { + "_id": "r4", + "i1": "'fashion'", + "i2": "", + "o1": "0.10" + }, + { + "_id": "r5", + "i1": "'home'", + "i2": "> 400", + "o1": "0.11" + }, + { + "_id": "r6", + "i1": "'home'", + "i2": "", + "o1": "0.07" + }, + { + "_id": "r7", + "i1": "", + "i2": "", + "o1": "0.05" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Category", + "field": "product.category" + }, + { + "id": "i2", + "name": "Sales Amount", + "field": "sales.amount" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Base Commission Rate", + "field": "commission.baseRate" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "productCategory", + "name": "productCategoryRates", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r8", + "i3": "> 4.5", + "i4": "> 95", + "o2": "0.02" + }, + { + "_id": "r9", + "i3": "> 4.0", + "i4": "> 90", + "o2": "0.01" + }, + { + "_id": "r10", + "i3": "< 3.0", + "i4": "< 80", + "o2": "-0.02" + }, + { + "_id": "r11", + "i3": "", + "i4": "", + "o2": "0" + } + ], + "inputs": [ + { + "id": "i3", + "name": "Rating", + "field": "seller.rating" + }, + { + "id": "i4", + "name": "Fulfillment Rate", + "field": "seller.fulfillmentRate" + } + ], + "outputs": [ + { + "id": "o2", + "name": "Performance Adjustment", + "field": "commission.performanceAdjustment" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "sellerPerformance", + "name": "sellerPerformanceAdjustment", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "isPromotionActive", + "value": "date(promotion.startDate) <= date('now') and date('now') <= date(promotion.endDate)" + }, + { + "id": "e2", + "key": "volumeMultiplier", + "value": "sales.volume > 100 ? 1.2 : 1.0" + }, + { + "id": "e3", + "key": "promotionAdjustment", + "value": "$.isPromotionActive ? 0.03 : 0" + }, + { + "id": "e4", + "key": "finalCommissionRate", + "value": "(commission.baseRate + commission.performanceAdjustment + $.promotionAdjustment) * $.volumeMultiplier" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "promotionalPeriod", + "name": "promotionalAdjustment", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "e1", + "sourceId": "input", + "targetId": "productCategory", + "type": "edge" + }, + { + "id": "e2", + "sourceId": "productCategory", + "targetId": "sellerPerformance", + "type": "edge" + }, + { + "id": "e3", + "sourceId": "sellerPerformance", + "targetId": "promotionalPeriod", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/dynamic-shipping-cost-calculator.json b/test-data/graphs/dynamic-shipping-cost-calculator.json new file mode 100644 index 00000000..1ef1c67b --- /dev/null +++ b/test-data/graphs/dynamic-shipping-cost-calculator.json @@ -0,0 +1,378 @@ +{ + "tests": [ + { + "input": { + "shippingType": "express", + "weight": 25, + "length": 40, + "width": 30, + "height": 20, + "distance": 250, + "customerTier": "gold" + }, + "output": { + "baseRate": 30, + "currentSeason": "summer", + "customerTier": "gold", + "dimensionalWeight": 4.8, + "distance": 250, + "distanceFactor": 2.5, + "effectiveWeight": 25, + "finalPrice": 35.4375, + "height": 20, + "length": 40, + "shippingType": "express", + "tierDiscount": 0.9, + "weight": 25, + "width": 30 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'standard'", + "i1-2": "< 20", + "o1-1": "10" + }, + { + "_id": "r1-2", + "i1-1": "'standard'", + "i1-2": "[20..50]", + "o1-1": "15" + }, + { + "_id": "r1-3", + "i1-1": "'standard'", + "i1-2": "> 50", + "o1-1": "25" + }, + { + "_id": "r1-4", + "i1-1": "'express'", + "i1-2": "< 20", + "o1-1": "20" + }, + { + "_id": "r1-5", + "i1-1": "'express'", + "i1-2": "[20..50]", + "o1-1": "30" + }, + { + "_id": "r1-6", + "i1-1": "'express'", + "i1-2": "> 50", + "o1-1": "45" + }, + { + "_id": "r1-7", + "i1-1": "'priority'", + "i1-2": "< 20", + "o1-1": "35" + }, + { + "_id": "r1-8", + "i1-1": "'priority'", + "i1-2": "[20..50]", + "o1-1": "50" + }, + { + "_id": "r1-9", + "i1-1": "'priority'", + "i1-2": "> 50", + "o1-1": "75" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Shipping Type", + "field": "shippingType" + }, + { + "id": "i1-2", + "name": "Weight (kg)", + "field": "weight" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Base Rate", + "field": "baseRate" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "base_rate_calculation", + "position": { + "x": 430, + "y": 65 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "< 80", + "o3-1": "'winter'" + }, + { + "_id": "r3-2", + "i3-1": "> 355", + "o3-1": "'winter'" + }, + { + "_id": "r3-3", + "i3-1": "> 172 and < 265", + "o3-1": "'summer'" + }, + { + "_id": "r3-4", + "i3-1": "", + "o3-1": "'regular'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Day of Year", + "field": "dayOfYear('now')" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Current Season", + "field": "currentSeason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt3", + "name": "determine_season", + "position": { + "x": 430, + "y": 163 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "dimensionalWeight", + "value": "(length * width * height) / 5000" + }, + { + "id": "e1-2", + "key": "effectiveWeight", + "value": "max([weight, $.dimensionalWeight])" + }, + { + "id": "e1-3", + "key": "distanceFactor", + "value": "distance / 100" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculate_factors", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'platinum'", + "i2-2": "'winter'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 0.8", + "o2-2": "0.8" + }, + { + "_id": "r2-2", + "i2-1": "'platinum'", + "i2-2": "'summer'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 0.8", + "o2-2": "0.8" + }, + { + "_id": "r2-3", + "i2-1": "'platinum'", + "i2-2": "'regular'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 0.8", + "o2-2": "0.8" + }, + { + "_id": "r2-4", + "i2-1": "'gold'", + "i2-2": "'winter'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 0.9 * 1.1", + "o2-2": "0.9" + }, + { + "_id": "r2-5", + "i2-1": "'gold'", + "i2-2": "'summer'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 0.9 * 1.05", + "o2-2": "0.9" + }, + { + "_id": "r2-6", + "i2-1": "'gold'", + "i2-2": "'regular'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 0.9", + "o2-2": "0.9" + }, + { + "_id": "r2-7", + "i2-1": "'silver'", + "i2-2": "'winter'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 0.95 * 1.1", + "o2-2": "0.95" + }, + { + "_id": "r2-8", + "i2-1": "'silver'", + "i2-2": "'summer'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 0.95 * 1.05", + "o2-2": "0.95" + }, + { + "_id": "r2-9", + "i2-1": "'silver'", + "i2-2": "'regular'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 0.95", + "o2-2": "0.95" + }, + { + "_id": "r2-10", + "i2-1": "", + "i2-2": "'winter'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 1.1", + "o2-2": "1" + }, + { + "_id": "r2-11", + "i2-1": "", + "i2-2": "'summer'", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1) * 1.05", + "o2-2": "1" + }, + { + "_id": "r2-12", + "i2-1": "", + "i2-2": "", + "o2-1": "baseRate * (effectiveWeight / weight) * (1 + distanceFactor * 0.1)", + "o2-2": "1" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Customer Tier", + "field": "customerTier" + }, + { + "id": "i2-2", + "name": "Season", + "field": "currentSeason" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Final Price", + "field": "finalPrice" + }, + { + "id": "o2-2", + "name": "Tier Discount", + "field": "tierDiscount" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "calculate_final_price", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ip1", + "targetId": "dt3", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "dt3", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed5", + "sourceId": "ex1", + "targetId": "dt2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/dynamic-tarrif-engine.json b/test-data/graphs/dynamic-tarrif-engine.json new file mode 100644 index 00000000..bf55a09d --- /dev/null +++ b/test-data/graphs/dynamic-tarrif-engine.json @@ -0,0 +1,289 @@ +{ + "tests": [ + { + "input": { + "userProfile": "premium", + "serviceType": "calls", + "timePeriod": "peak", + "locationType": "domestic", + "currency": "EUR", + "usage": { + "amount": 15, + "unit": "minutes" + }, + "userId": "USR123456", + "timestamp": "2025-03-20T14:30:00Z" + }, + "output": { + "baseTariff": 0.05, + "currency": "EUR", + "finalTariff": 0.048, + "rulesSummary": [ + "Base rate: 0.05 per unit", + "Premium user call discount", + "Peak hour domestic rate" + ] + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "'premium'", + "i2": "'calls'", + "o1": "0.8", + "o2": "'Premium user call discount'" + }, + { + "_id": "r2", + "i1": "'premium'", + "i2": "'data'", + "o1": "0.9", + "o2": "'Premium user data discount'" + }, + { + "_id": "r3", + "i1": "'premium'", + "i2": "'messaging'", + "o1": "0.7", + "o2": "'Premium user messaging discount'" + }, + { + "_id": "r4", + "i1": "'business'", + "i2": "'calls'", + "o1": "0.85", + "o2": "'Business user call discount'" + }, + { + "_id": "r5", + "i1": "'business'", + "i2": "'data'", + "o1": "0.8", + "o2": "'Business user data discount'" + }, + { + "_id": "r6", + "i1": "'business'", + "i2": "'messaging'", + "o1": "0.6", + "o2": "'Business user messaging discount'" + }, + { + "_id": "r7", + "i1": "'standard'", + "i2": "", + "o1": "1.0", + "o2": "'Standard rate applied'" + }, + { + "_id": "r8", + "i1": "", + "i2": "", + "o1": "1.0", + "o2": "'Default rate applied'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "User Profile", + "field": "userProfile" + }, + { + "id": "i2", + "name": "Service Type", + "field": "serviceType" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Profile Multiplier", + "field": "profileMultiplier" + }, + { + "id": "o2", + "name": "Rule Applied", + "field": "profileRuleApplied" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "profileRules", + "name": "userProfileRules", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "'peak'", + "i2": "'roaming'", + "o1": "1.5", + "o2": "'Peak hour roaming surcharge'" + }, + { + "_id": "r2", + "i1": "'peak'", + "i2": "'domestic'", + "o1": "1.2", + "o2": "'Peak hour domestic rate'" + }, + { + "_id": "r3", + "i1": "'off-peak'", + "i2": "'roaming'", + "o1": "1.3", + "o2": "'Off-peak roaming rate'" + }, + { + "_id": "r4", + "i1": "'off-peak'", + "i2": "'domestic'", + "o1": "0.9", + "o2": "'Off-peak domestic discount'" + }, + { + "_id": "r5", + "i1": "'weekend'", + "i2": "'roaming'", + "o1": "1.2", + "o2": "'Weekend roaming rate'" + }, + { + "_id": "r6", + "i1": "'weekend'", + "i2": "'domestic'", + "o1": "0.8", + "o2": "'Weekend domestic discount'" + }, + { + "_id": "r7", + "i1": "", + "i2": "", + "o1": "1.0", + "o2": "'Default time/location rate'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Time Period", + "field": "timePeriod" + }, + { + "id": "i2", + "name": "Location Type", + "field": "locationType" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Time Location Multiplier", + "field": "timeLocationMultiplier" + }, + { + "id": "o2", + "name": "Rule Applied", + "field": "timeLocationRuleApplied" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "timeLocationRules", + "name": "timeLocationRules", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "baseTariff", + "value": "serviceType == 'calls' ? 0.05 : (serviceType == 'data' ? 0.02 : 0.01)" + }, + { + "id": "e2", + "key": "finalTariff", + "value": "$.baseTariff * profileMultiplier * timeLocationMultiplier" + }, + { + "id": "e3", + "key": "currency", + "value": "currency ?? 'USD'" + }, + { + "id": "e4", + "key": "rulesSummary", + "value": "[`Base rate: ${$.baseTariff} per unit`, profileRuleApplied, timeLocationRuleApplied]" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "calculateFinalTariff", + "name": "calculateFinalTariff", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "e1", + "sourceId": "input", + "targetId": "profileRules", + "type": "edge" + }, + { + "id": "e2", + "sourceId": "profileRules", + "targetId": "timeLocationRules", + "type": "edge" + }, + { + "id": "e3", + "sourceId": "timeLocationRules", + "targetId": "calculateFinalTariff", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/dynamic-ticket-pricing.json b/test-data/graphs/dynamic-ticket-pricing.json new file mode 100644 index 00000000..3f941aec --- /dev/null +++ b/test-data/graphs/dynamic-ticket-pricing.json @@ -0,0 +1,325 @@ +{ + "tests": [ + { + "input": { + "flightId": "FL-123", + "routeId": "JFK-LAX", + "daysToDepature": 1, + "basePrice": 250, + "availableSeats": 5, + "totalSeats": 180, + "demandForecast": 95, + "avgCompetitorPrice": 25 + }, + "output": { + "finalPrice": 536.25, + "priceStrategy": "premium" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "< 3", + "o1-1": "1.5", + "o1-2": "'high'" + }, + { + "_id": "r1-2", + "i1-1": ">= 3 and <= 7", + "o1-1": "1.2", + "o1-2": "'medium'" + }, + { + "_id": "r1-3", + "i1-1": "> 7 and <= 14", + "o1-1": "1.1", + "o1-2": "'low'" + }, + { + "_id": "r1-4", + "i1-1": "> 14", + "o1-1": "1.0", + "o1-2": "'baseline'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Days To Departure", + "field": "daysToDepature" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Urgency Multiplier", + "field": "urgencyMultiplier" + }, + { + "id": "o1-2", + "name": "Urgency Level", + "field": "urgencyLevel" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "time_urgency", + "position": { + "x": 430, + "y": 292.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "availabilityRatio", + "value": "availableSeats / totalSeats" + }, + { + "id": "e1-2", + "key": "demandIndex", + "value": "demandForecast / 100" + }, + { + "id": "e1-3", + "key": "competitiveIndex", + "value": "avgCompetitorPrice / basePrice" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculate_factors", + "position": { + "x": 750, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "< 0.2", + "i2-2": "> 0.8", + "o2-1": "1.3", + "o2-2": "'very_high'" + }, + { + "_id": "r2-2", + "i2-1": ">= 0.2 and < 0.4", + "i2-2": "> 0.7", + "o2-1": "1.2", + "o2-2": "'high'" + }, + { + "_id": "r2-3", + "i2-1": ">= 0.4 and < 0.6", + "i2-2": ">= 0.5", + "o2-1": "1.1", + "o2-2": "'medium'" + }, + { + "_id": "r2-4", + "i2-1": ">= 0.6 and < 0.8", + "i2-2": "", + "o2-1": "0.95", + "o2-2": "'low'" + }, + { + "_id": "r2-5", + "i2-1": "", + "i2-2": "", + "o2-1": "0.9", + "o2-2": "'very_low'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Availability Ratio", + "field": "availabilityRatio" + }, + { + "id": "i2-2", + "name": "Demand Index", + "field": "demandIndex" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Inventory Multiplier", + "field": "inventoryMultiplier" + }, + { + "id": "o2-2", + "name": "Demand Level", + "field": "demandLevel" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "inventory_demand", + "position": { + "x": 1070, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "'high'", + "i3-2": "'very_high'", + "i3-3": "< 0.9", + "o3-1": "basePrice * urgencyMultiplier * inventoryMultiplier * 1.1", + "o3-2": "'premium'" + }, + { + "_id": "r3-2", + "i3-1": "'high','medium'", + "i3-2": "'high'", + "i3-3": "< 1.1", + "o3-1": "basePrice * urgencyMultiplier * inventoryMultiplier * 1.05", + "o3-2": "'competitive_high'" + }, + { + "_id": "r3-3", + "i3-1": "'medium','low'", + "i3-2": "'medium'", + "i3-3": "<= 1.2 and >= 0.8", + "o3-1": "basePrice * urgencyMultiplier * inventoryMultiplier", + "o3-2": "'match_market'" + }, + { + "_id": "r3-4", + "i3-1": "'low','baseline'", + "i3-2": "'low'", + "i3-3": "> 1.2", + "o3-1": "basePrice * urgencyMultiplier * inventoryMultiplier * 0.95", + "o3-2": "'competitive_low'" + }, + { + "_id": "r3-5", + "i3-1": "'baseline'", + "i3-2": "'very_low'", + "i3-3": "> 1.3", + "o3-1": "basePrice * urgencyMultiplier * inventoryMultiplier * 0.9", + "o3-2": "'discount'" + }, + { + "_id": "r3-6", + "i3-1": "", + "i3-2": "", + "i3-3": "", + "o3-1": "basePrice * urgencyMultiplier * inventoryMultiplier", + "o3-2": "'match_market'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Urgency Level", + "field": "urgencyLevel" + }, + { + "id": "i3-2", + "name": "Demand Level", + "field": "demandLevel" + }, + { + "id": "i3-3", + "name": "Competitive Index", + "field": "competitiveIndex" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Final Price", + "field": "finalPrice" + }, + { + "id": "o3-2", + "name": "Price Strategy", + "field": "priceStrategy" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt3", + "name": "final_pricing", + "position": { + "x": 1390, + "y": 292.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ex1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "dt2", + "targetId": "dt3", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/environment-compliance-assessment.json b/test-data/graphs/environment-compliance-assessment.json new file mode 100644 index 00000000..69bd03d7 --- /dev/null +++ b/test-data/graphs/environment-compliance-assessment.json @@ -0,0 +1,386 @@ +{ + "tests": [ + { + "input": { + "industry": "manufacturing", + "location": { + "country": "United States", + "region": "midwest", + "city": "Detroit" + }, + "emissions": { + "carbonDioxideMetricTons": 18500, + "methaneMetricTons": 120, + "nitrousOxideMetricTons": 45 + }, + "production": { + "volume": 100, + "units": "million_units" + }, + "waste": { + "hazardousWasteMetricTons": 50, + "nonHazardousWasteMetricTons": 350, + "recycledPercentage": 22, + "violations": 1 + }, + "water": { + "consumptionKiloliters": 250000, + "treatedPercentage": 85, + "violations": 0 + }, + "audits": { + "lastAuditDate": "2025-01-15", + "previousFindings": 3, + "resolvedFindings": 2 + } + }, + "output": { + "assessment": { + "emissionThreshold": 150, + "industryRiskLevel": "medium" + }, + "audits": { + "lastAuditDate": "2025-01-15", + "previousFindings": 3, + "resolvedFindings": 2 + }, + "carbonIntensity": 185, + "compliance": { + "actionTimeframe": "60-days", + "recommendation": "Medium-risk industry with significant threshold exceedance requires remediation plan within 60 days.", + "status": "non-compliant" + }, + "emissions": { + "carbonDioxideMetricTons": 18500, + "methaneMetricTons": 120, + "nitrousOxideMetricTons": 45 + }, + "exceededThreshold": true, + "hasWasteViolations": true, + "hasWaterViolations": false, + "industry": "manufacturing", + "location": { + "city": "Detroit", + "country": "United States", + "region": "midwest" + }, + "percentOverThreshold": 23.333333333333332, + "production": { + "units": "million_units", + "volume": 100 + }, + "waste": { + "hazardousWasteMetricTons": 50, + "nonHazardousWasteMetricTons": 350, + "recycledPercentage": 22, + "violations": 1 + }, + "water": { + "consumptionKiloliters": 250000, + "treatedPercentage": 85, + "violations": 0 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "inputNode", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "industry": "'energy', 'oil', 'gas', 'mining', 'chemical'", + "region": "", + "industryRiskLevel": "'high'", + "emissionThreshold": "100" + }, + { + "_id": "rule2", + "industry": "'manufacturing', 'automotive', 'construction'", + "region": "", + "industryRiskLevel": "'medium'", + "emissionThreshold": "150" + }, + { + "_id": "rule3", + "industry": "'transportation', 'logistics'", + "region": "'california', 'eu', 'uk'", + "industryRiskLevel": "'medium'", + "emissionThreshold": "120" + }, + { + "_id": "rule4", + "industry": "'transportation', 'logistics'", + "region": "", + "industryRiskLevel": "'medium-low'", + "emissionThreshold": "200" + }, + { + "_id": "rule5", + "industry": "'agriculture', 'food processing'", + "region": "", + "industryRiskLevel": "'medium-low'", + "emissionThreshold": "180" + }, + { + "_id": "rule6", + "industry": "'technology', 'services', 'retail', 'healthcare'", + "region": "", + "industryRiskLevel": "'low'", + "emissionThreshold": "250" + }, + { + "_id": "rule7", + "industry": "", + "region": "", + "industryRiskLevel": "'undefined'", + "emissionThreshold": "200" + } + ], + "inputs": [ + { + "id": "industry", + "name": "Industry", + "field": "industry" + }, + { + "id": "region", + "name": "Region", + "field": "location.region" + } + ], + "outputs": [ + { + "id": "industryRiskLevel", + "name": "Industry Risk Level", + "field": "assessment.industryRiskLevel" + }, + { + "id": "emissionThreshold", + "name": "Emission Threshold", + "field": "assessment.emissionThreshold" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "industryRiskTable", + "name": "industryRiskAssessment", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "carbonIntensity", + "value": "emissions.carbonDioxideMetricTons / (production.volume ?? 1)" + }, + { + "id": "expr2", + "key": "exceededThreshold", + "value": "$.carbonIntensity > (assessment.emissionThreshold ?? 200)" + }, + { + "id": "expr3", + "key": "percentOverThreshold", + "value": "$.exceededThreshold ? (($.carbonIntensity - assessment.emissionThreshold) / assessment.emissionThreshold * 100) : 0" + }, + { + "id": "expr4", + "key": "hasWasteViolations", + "value": "waste.violations > 0" + }, + { + "id": "expr5", + "key": "hasWaterViolations", + "value": "water.violations > 0" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "emissionsEvaluation", + "name": "emissionsEvaluation", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "cs1", + "i1": "'high'", + "i2": "true", + "i3": "> 10", + "o1": "'non-compliant'", + "o2": "'immediate'", + "o3": "'High-risk industry with significant threshold exceedance requires immediate remediation plan and potential reporting to authorities.'" + }, + { + "_id": "cs2", + "i1": "'high'", + "i2": "true", + "i3": "< 10", + "o1": "'at-risk'", + "o2": "'30-days'", + "o3": "'High-risk industry with minor threshold exceedance requires action plan within 30 days.'" + }, + { + "_id": "cs3", + "i1": "'high'", + "i2": "false", + "i3": "", + "o1": "'compliant-with-monitoring'", + "o2": "'quarterly'", + "o3": "'High-risk industry requires quarterly monitoring and reporting despite current compliance.'" + }, + { + "_id": "cs4", + "i1": "'medium', 'medium-low'", + "i2": "true", + "i3": "> 20", + "o1": "'non-compliant'", + "o2": "'60-days'", + "o3": "'Medium-risk industry with significant threshold exceedance requires remediation plan within 60 days.'" + }, + { + "_id": "cs5", + "i1": "'medium', 'medium-low'", + "i2": "true", + "i3": "< 20", + "o1": "'at-risk'", + "o2": "'90-days'", + "o3": "'Medium-risk industry with minor threshold exceedance requires review within 90 days.'" + }, + { + "_id": "cs6", + "i1": "'medium', 'medium-low'", + "i2": "false", + "i3": "", + "o1": "'compliant'", + "o2": "'bi-annual'", + "o3": "'Medium-risk industry is currently compliant with bi-annual review recommendation.'" + }, + { + "_id": "cs7", + "i1": "'low'", + "i2": "true", + "i3": "", + "o1": "'at-risk'", + "o2": "'120-days'", + "o3": "'Low-risk industry exceeding thresholds requires review within 120 days.'" + }, + { + "_id": "cs8", + "i1": "'low'", + "i2": "false", + "i3": "", + "o1": "'compliant'", + "o2": "'annual'", + "o3": "'Low-risk industry is compliant with annual review recommendation.'" + }, + { + "_id": "cs9", + "i1": "", + "i2": "", + "i3": "", + "o1": "'undefined'", + "o2": "'90-days'", + "o3": "'Industry risk level undefined. Recommended assessment within 90 days.'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Industry Risk Level", + "field": "assessment.industryRiskLevel" + }, + { + "id": "i2", + "name": "Exceeded Threshold", + "field": "exceededThreshold" + }, + { + "id": "i3", + "name": "Percent Over Threshold", + "field": "percentOverThreshold" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Compliance Status", + "field": "compliance.status" + }, + { + "id": "o2", + "name": "Required Action Timeframe", + "field": "compliance.actionTimeframe" + }, + { + "id": "o3", + "name": "Recommendation", + "field": "compliance.recommendation" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "complianceStatus", + "name": "complianceStatus", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "inputNode", + "targetId": "industryRiskTable", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "industryRiskTable", + "targetId": "emissionsEvaluation", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "emissionsEvaluation", + "targetId": "complianceStatus", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/flash-sale-eligibility.json b/test-data/graphs/flash-sale-eligibility.json new file mode 100644 index 00000000..7766dfa9 --- /dev/null +++ b/test-data/graphs/flash-sale-eligibility.json @@ -0,0 +1,366 @@ +{ + "tests": [ + { + "input": { + "productId": "PROD-12345", + "category": "Electronics", + "currentInventory": 75, + "profitMargin": 0.28, + "season": "summer", + "currentMonth": 7, + "sellerRating": 4.5, + "sellerHistoricalSales": 2500 + }, + "output": { + "category": "Electronics", + "currentInventory": 75, + "currentMonth": 7, + "discountPercentage": 15, + "eligibilityReason": "Product fully qualifies for flash sale", + "initialCheckReason": "Sufficient inventory and margin", + "isEligibleForFlashSale": true, + "isInSeason": true, + "isQualifiedSeller": true, + "passesInitialCheck": true, + "productId": "PROD-12345", + "profitMargin": 0.28, + "season": "summer", + "seasonReason": "Summer product in summer months", + "seasonalityFactor": 1.2, + "sellerFactor": 1.5, + "sellerHistoricalSales": 2500, + "sellerRating": 4.5 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"productId\": { \"type\": \"string\" },\n \"category\": { \"type\": \"string\" },\n \"currentInventory\": { \"type\": \"number\" },\n \"profitMargin\": { \"type\": \"number\" },\n \"season\": { \"type\": \"string\" },\n \"currentMonth\": { \"type\": \"number\" },\n \"sellerRating\": { \"type\": \"number\" },\n \"sellerHistoricalSales\": { \"type\": \"number\" }\n },\n \"required\": [\"productId\", \"category\", \"currentInventory\", \"profitMargin\", \"season\", \"currentMonth\", \"sellerRating\", \"sellerHistoricalSales\"]\n}" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": ">= 50", + "i2": ">= 0.25", + "o1": "true", + "o2": "'Sufficient inventory and margin'" + }, + { + "_id": "r2", + "i1": ">= 100", + "i2": ">= 0.15", + "o1": "true", + "o2": "'High inventory with acceptable margin'" + }, + { + "_id": "r3", + "i1": "< 20", + "i2": "", + "o1": "false", + "o2": "'Insufficient inventory for flash sale'" + }, + { + "_id": "r4", + "i1": "", + "i2": "< 0.1", + "o1": "false", + "o2": "'Margin too low for promotion'" + }, + { + "_id": "r5", + "i1": "", + "i2": "", + "o1": "false", + "o2": "'Default: Does not meet primary criteria'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Current Inventory", + "field": "currentInventory" + }, + { + "id": "i2", + "name": "Profit Margin", + "field": "profitMargin" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Passes Initial Check", + "field": "passesInitialCheck" + }, + { + "id": "o2", + "name": "Initial Check Reason", + "field": "initialCheckReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "checkInventoryAndMargin", + "name": "checkInventoryAndMargin", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "'summer'", + "i2": "6, 7, 8", + "o1": "true", + "o2": "'Summer product in summer months'" + }, + { + "_id": "r2", + "i1": "'winter'", + "i2": "1, 2, 12", + "o1": "true", + "o2": "'Winter product in winter months'" + }, + { + "_id": "r3", + "i1": "'fall'", + "i2": "9, 10, 11", + "o1": "true", + "o2": "'Fall product in fall months'" + }, + { + "_id": "r4", + "i1": "'spring'", + "i2": "3, 4, 5", + "o1": "true", + "o2": "'Spring product in spring months'" + }, + { + "_id": "r5", + "i1": "'all-year'", + "i2": "", + "o1": "true", + "o2": "'Product available year-round'" + }, + { + "_id": "r6", + "i1": "", + "i2": "", + "o1": "false", + "o2": "'Product out of season'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Season", + "field": "season" + }, + { + "id": "i2", + "name": "Current Month", + "field": "currentMonth" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Is In Season", + "field": "isInSeason" + }, + { + "id": "o2", + "name": "Season Reason", + "field": "seasonReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "checkSeasonality", + "name": "checkSeasonality", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "isQualifiedSeller", + "value": "sellerRating >= 4.0 and sellerHistoricalSales >= 1000" + }, + { + "id": "e2", + "key": "seasonalityFactor", + "value": "isInSeason ? 1.2 : 0.8" + }, + { + "id": "e3", + "key": "sellerFactor", + "value": "$.isQualifiedSeller ? 1.5 : (sellerRating >= 3.5 ? 1.0 : 0.5)" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "checkSellerQuality", + "name": "checkSellerQuality", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "passesInitialCheck == true", + "i2": "isInSeason == true", + "i3": "isQualifiedSeller == true", + "o1": "true", + "o2": "'Product fully qualifies for flash sale'", + "o3": "15" + }, + { + "_id": "r2", + "i1": "passesInitialCheck == true", + "i2": "isInSeason == true", + "i3": "isQualifiedSeller == false", + "o1": "true", + "o2": "'Seasonal product with sufficient inventory/margin'", + "o3": "10" + }, + { + "_id": "r3", + "i1": "passesInitialCheck == true", + "i2": "isInSeason == false", + "i3": "isQualifiedSeller == true", + "o1": "true", + "o2": "'Off-season product from top seller'", + "o3": "8" + }, + { + "_id": "r4", + "i1": "passesInitialCheck == false", + "i2": "", + "i3": "isQualifiedSeller == true and currentInventory >= 30", + "o1": "true", + "o2": "'Top seller exemption applied'", + "o3": "5" + }, + { + "_id": "r5", + "i1": "", + "i2": "", + "i3": "", + "o1": "false", + "o2": "'Product does not qualify for flash sale'", + "o3": "0" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Initial Check", + "field": "passesInitialCheck" + }, + { + "id": "i2", + "name": "Seasonality", + "field": "isInSeason" + }, + { + "id": "i3", + "name": "Seller Quality", + "field": "isQualifiedSeller" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Is Eligible For Flash Sale", + "field": "isEligibleForFlashSale" + }, + { + "id": "o2", + "name": "Eligibility Reason", + "field": "eligibilityReason" + }, + { + "id": "o3", + "name": "Discount Percentage", + "field": "discountPercentage" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "determineEligibility", + "name": "determineEligibility", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "checkInventoryAndMargin", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "checkInventoryAndMargin", + "targetId": "checkSeasonality", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "checkSeasonality", + "targetId": "checkSellerQuality", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "checkSellerQuality", + "targetId": "determineEligibility", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/flight-ancillary-recommendations.json b/test-data/graphs/flight-ancillary-recommendations.json new file mode 100644 index 00000000..8d777732 --- /dev/null +++ b/test-data/graphs/flight-ancillary-recommendations.json @@ -0,0 +1,436 @@ +{ + "tests": [ + { + "input": { + "customerProfile": { + "id": "cust-12345", + "loyaltyTier": "gold", + "travelFrequency": "frequent", + "preferredLanguage": "en", + "preferredCurrency": "USD" + }, + "route": { + "origin": "JFK", + "destination": "international", + "flightDurationMinutes": 480, + "hasAirportLounge": true, + "departureTime": "2025-04-15T08:30:00Z", + "returnTime": "2025-04-22T15:45:00Z" + }, + "travelPurpose": "business", + "tripDetails": { + "passengers": 1, + "cabinClass": "economy", + "dateFlexibility": "fixed" + }, + "previousPurchases": [ + { + "bookingId": "bkg-9876", + "productType": "seat", + "purchaseDate": "2024-12-10T14:22:00Z", + "productDetails": { + "seatType": "extra_legroom", + "amount": 35 + } + }, + { + "bookingId": "bkg-8765", + "productType": "wifi", + "purchaseDate": "2024-11-05T09:15:00Z", + "productDetails": { + "packageType": "full_flight", + "amount": 19.99 + } + } + ] + }, + "output": { + "recommendations": [ + { + "priority": 5, + "productType": "lounge" + }, + { + "priority": 4, + "productType": "priority_boarding" + }, + { + "priority": 3, + "productType": "wifi" + }, + { + "priority": 4, + "productType": "lounge" + }, + { + "priority": 3, + "productType": "travel_insurance" + }, + { + "priority": 2, + "productType": "premium_meal" + }, + { + "priority": 4, + "productType": "fast_track_security" + } + ] + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": ">= 240", + "o1-1": "'long'" + }, + { + "_id": "r1-2", + "i1-1": ">= 120 and < 240", + "o1-1": "'medium'" + }, + { + "_id": "r1-3", + "i1-1": "< 120", + "o1-1": "'short'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Flight Duration Minutes", + "field": "route.flightDurationMinutes" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Duration Category", + "field": "flightDurationCategory" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "categorize_flight_duration", + "position": { + "x": 430, + "y": 292.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "isPremiumCustomer", + "value": "customerProfile.loyaltyTier == 'gold' or customerProfile.loyaltyTier == 'platinum'" + }, + { + "id": "e1-2", + "key": "hasBoughtBaggage", + "value": "some(previousPurchases ?? [], #.productType == 'baggage')" + }, + { + "id": "e1-3", + "key": "hasBoughtMeals", + "value": "some(previousPurchases ?? [], #.productType == 'meal')" + }, + { + "id": "e1-4", + "key": "hasBoughtSeats", + "value": "some(previousPurchases ?? [], #.productType == 'seat')" + }, + { + "id": "e1-5", + "key": "hasBoughtLounge", + "value": "some(previousPurchases ?? [], #.productType == 'lounge')" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculate_customer_attributes", + "position": { + "x": 750, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'business'", + "i2-2": "'long'", + "i2-3": "isPremiumCustomer", + "o2-1": "'lounge'", + "o2-2": "5" + }, + { + "_id": "r2-2", + "i2-1": "'business'", + "i2-2": "'medium', 'long'", + "i2-3": "", + "o2-1": "'priority_boarding'", + "o2-2": "4" + }, + { + "_id": "r2-3", + "i2-1": "'business'", + "i2-2": "", + "i2-3": "", + "o2-1": "'wifi'", + "o2-2": "3" + }, + { + "_id": "r2-4", + "i2-1": "'leisure'", + "i2-2": "'long'", + "i2-3": "", + "o2-1": "'extra_baggage'", + "o2-2": "5" + }, + { + "_id": "r2-5", + "i2-1": "'leisure'", + "i2-2": "'medium', 'long'", + "i2-3": "!hasBoughtMeals", + "o2-1": "'meal'", + "o2-2": "4" + }, + { + "_id": "r2-6", + "i2-1": "'leisure'", + "i2-2": "", + "i2-3": "!hasBoughtSeats", + "o2-1": "'seat_selection'", + "o2-2": "3" + }, + { + "_id": "r2-7", + "i2-1": "'family'", + "i2-2": "'medium', 'long'", + "i2-3": "", + "o2-1": "'family_seating'", + "o2-2": "5" + }, + { + "_id": "r2-8", + "i2-1": "'family'", + "i2-2": "", + "i2-3": "!hasBoughtBaggage", + "o2-1": "'extra_baggage'", + "o2-2": "4" + }, + { + "_id": "r2-9", + "i2-1": "'family'", + "i2-2": "'long'", + "i2-3": "", + "o2-1": "'entertainment_package'", + "o2-2": "3" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Travel Purpose", + "field": "travelPurpose" + }, + { + "id": "i2-2", + "name": "Flight Duration", + "field": "flightDurationCategory" + }, + { + "id": "i2-3", + "name": "Customer Attributes", + "field": "" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Product", + "field": "productType" + }, + { + "id": "o2-2", + "name": "Priority", + "field": "priority" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "recommendations.base", + "executionMode": "single", + "passThorough": false + }, + "id": "dt2", + "name": "base_recommendations", + "position": { + "x": 1070, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "r3-1", + "i3-1": "route.hasAirportLounge and !hasBoughtLounge", + "i3-2": "isPremiumCustomer", + "o3-1": "'lounge'", + "o3-2": "4" + }, + { + "_id": "r3-2", + "i3-1": "route.destination == 'international'", + "i3-2": "", + "o3-1": "'travel_insurance'", + "o3-2": "3" + }, + { + "_id": "r3-3", + "i3-1": "flightDurationCategory == 'long' and !hasBoughtMeals", + "i3-2": "", + "o3-1": "'premium_meal'", + "o3-2": "2" + }, + { + "_id": "r3-4", + "i3-1": "customerProfile.travelFrequency == 'frequent' and travelPurpose == 'business'", + "i3-2": "", + "o3-1": "'fast_track_security'", + "o3-2": "4" + }, + { + "_id": "r3-5", + "i3-1": "route.destination == 'beach' or route.destination == 'resort'", + "i3-2": "travelPurpose == 'leisure'", + "o3-1": "'excursion_package'", + "o3-2": "3" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Route Attributes", + "field": "" + }, + { + "id": "i3-2", + "name": "Customer Context", + "field": "" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Additional Product", + "field": "productType" + }, + { + "id": "o3-2", + "name": "Priority", + "field": "priority" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "recommendations.additional", + "executionMode": "single", + "passThorough": false + }, + "id": "dt3", + "name": "additional_recommendations", + "position": { + "x": 1390, + "y": 292.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "0a0fbafe-0a16-445a-99f8-c8b4341ef370", + "key": "recommendations", + "value": "flatten(values(recommendations))" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "8cb0ce16-c426-4988-b39f-d122499bc1fd", + "name": "join_recommendations", + "position": { + "x": 1710, + "y": 292.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ex1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "dt2", + "targetId": "dt3", + "type": "edge" + }, + { + "id": "d0ef3f95-c4cf-4311-8ae0-6d2fc9771730", + "sourceId": "dt3", + "type": "edge", + "targetId": "8cb0ce16-c426-4988-b39f-d122499bc1fd" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/flight-dispatch-decision-system.json b/test-data/graphs/flight-dispatch-decision-system.json new file mode 100644 index 00000000..38ba4a6d --- /dev/null +++ b/test-data/graphs/flight-dispatch-decision-system.json @@ -0,0 +1,455 @@ +{ + "tests": [ + { + "input": { + "weather": { + "windSpeed": 90, + "visibility": 6500, + "precipitation": "light", + "temperature": 15 + }, + "aircraft": { + "emptyWeight": 41500, + "maxTakeoffWeight": 78000, + "fuelReserves": 1.5, + "maintenanceRequired": false, + "type": "B737-800" + }, + "manifest": { + "passengers": [ + "P001", + "P002", + "P003", + "P004", + "P005", + "P006", + "P007", + "P008", + "P009", + "P010" + ], + "cargoWeight": 2500 + }, + "crew": { + "restCompliant": true, + "members": [ + "C001", + "C002", + "C003" + ] + }, + "flight": { + "number": "FL123", + "origin": "LAX", + "destination": "JFK", + "scheduledDeparture": "2025-03-19T08:00:00Z" + } + }, + "output": { + "dispatchReasons": [ + { + "flag": false, + "reason": "Extreme wind and low visibility" + } + ], + "dispatchSummary": "Flight dispatch denied", + "failedCriteria": [ + "weather" + ], + "isDispatchable": false + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "inputNode", + "name": "flightDispatchRequest", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "windSpeed": "> 45", + "visibility": "< 10000", + "weatherFlag": "false", + "weatherReason": "'Extreme wind and low visibility'" + }, + { + "_id": "rule2", + "windSpeed": "> 45", + "visibility": "", + "weatherFlag": "false", + "weatherReason": "'Winds exceed aircraft limitations'" + }, + { + "_id": "rule3", + "windSpeed": "> 35", + "visibility": "< 5000", + "weatherFlag": "false", + "weatherReason": "'High winds with low visibility'" + }, + { + "_id": "rule4", + "windSpeed": "", + "visibility": "< 1000", + "weatherFlag": "false", + "weatherReason": "'Visibility below minimum requirements'" + }, + { + "_id": "rule5", + "windSpeed": "", + "visibility": "", + "weatherFlag": "true", + "weatherReason": "'Weather conditions acceptable'" + } + ], + "inputs": [ + { + "id": "windSpeed", + "name": "WindSpeed", + "field": "weather.windSpeed" + }, + { + "id": "visibility", + "name": "Visibility", + "field": "weather.visibility" + } + ], + "outputs": [ + { + "id": "weatherFlag", + "name": "WeatherFlag", + "field": "dispatch.weather.flag" + }, + { + "id": "weatherReason", + "name": "WeatherReason", + "field": "dispatch.weather.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "weatherEligibility", + "name": "weatherEligibility", + "position": { + "x": 750, + "y": -33 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "maintenance": "true", + "aircraftFlag": "false", + "aircraftReason": "'Aircraft requires maintenance'" + }, + { + "_id": "rule2", + "fuelReserves": "< 1", + "aircraftFlag": "false", + "aircraftReason": "'Insufficient fuel reserves'" + }, + { + "_id": "rule3", + "maintenance": "", + "fuelReserves": "", + "aircraftFlag": "true", + "aircraftReason": "'Aircraft is operational'" + } + ], + "inputs": [ + { + "id": "maintenance", + "name": "MaintenanceRequired", + "field": "aircraft.maintenanceRequired" + }, + { + "id": "fuelReserves", + "name": "FuelReserves", + "field": "aircraft.fuelReserves" + } + ], + "outputs": [ + { + "id": "aircraftFlag", + "name": "AircraftFlag", + "field": "dispatch.aircraft.flag" + }, + { + "id": "aircraftReason", + "name": "AircraftReason", + "field": "dispatch.aircraft.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "aircraftEligibility", + "name": "aircraftEligibility", + "position": { + "x": 750, + "y": 65 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "restCompliant": "false", + "crewFlag": "false", + "crewReason": "'Crew rest requirements not met'" + }, + { + "_id": "rule2", + "crewCount": "< 2", + "crewFlag": "false", + "crewReason": "'Insufficient crew members'" + }, + { + "_id": "rule3", + "restCompliant": "", + "crewCount": "", + "crewFlag": "true", + "crewReason": "'Crew requirements satisfied'" + } + ], + "inputs": [ + { + "id": "restCompliant", + "name": "CrewRestCompliant", + "field": "crew.restCompliant" + }, + { + "id": "crewCount", + "name": "CrewCount", + "field": "len(crew.members)" + } + ], + "outputs": [ + { + "id": "crewFlag", + "name": "CrewFlag", + "field": "dispatch.crew.flag" + }, + { + "id": "crewReason", + "name": "CrewReason", + "field": "dispatch.crew.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "crewEligibility", + "name": "crewEligibility", + "position": { + "x": 750, + "y": 163 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "totalPassengers", + "value": "len(manifest.passengers)" + }, + { + "id": "expr2", + "key": "passengerWeight", + "value": "$.totalPassengers * 85" + }, + { + "id": "expr3", + "key": "totalCargo", + "value": "manifest.cargoWeight" + }, + { + "id": "expr4", + "key": "estimatedTakeoffWeight", + "value": "aircraft.emptyWeight + $.totalCargo + $.passengerWeight" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "weightCalculations", + "name": "weightCalculations", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "takeoffWeight": "> aircraft.maxTakeoffWeight", + "weightFlag": "false", + "weightReason": "'Aircraft exceeds maximum takeoff weight'" + }, + { + "_id": "rule2", + "takeoffWeight": "", + "weightFlag": "true", + "weightReason": "'Weight within acceptable limits'" + } + ], + "inputs": [ + { + "id": "takeoffWeight", + "name": "TakeoffWeight", + "field": "estimatedTakeoffWeight" + } + ], + "outputs": [ + { + "id": "weightFlag", + "name": "WeightFlag", + "field": "dispatch.weight.flag" + }, + { + "id": "weightReason", + "name": "WeightReason", + "field": "dispatch.weight.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "weightEligibility", + "name": "weightEligibility", + "position": { + "x": 750, + "y": 261 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "isDispatchable", + "value": "all(values(dispatch), #.flag)" + }, + { + "id": "expr2", + "key": "dispatchReasons", + "value": "filter(values(dispatch), #.flag == false)" + }, + { + "id": "expr3", + "key": "dispatchSummary", + "value": "$.isDispatchable ? 'Flight is cleared for dispatch' : 'Flight dispatch denied'" + }, + { + "id": "expr4", + "key": "failedCriteria", + "value": "filter(keys(dispatch), dispatch[#].flag == false)" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dispatchSummary", + "name": "dispatchSummary", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge5", + "sourceId": "weightCalculations", + "targetId": "weightEligibility", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "weatherEligibility", + "targetId": "dispatchSummary", + "type": "edge" + }, + { + "id": "edge7", + "sourceId": "aircraftEligibility", + "targetId": "dispatchSummary", + "type": "edge" + }, + { + "id": "edge8", + "sourceId": "crewEligibility", + "targetId": "dispatchSummary", + "type": "edge" + }, + { + "id": "edge9", + "sourceId": "weightEligibility", + "targetId": "dispatchSummary", + "type": "edge" + }, + { + "id": "19843411-30e0-44f4-977d-ccffbfaf9635", + "sourceId": "inputNode", + "type": "edge", + "targetId": "weightCalculations" + }, + { + "id": "721e4054-5365-495b-b87c-8b10618ba5a3", + "sourceId": "weightCalculations", + "type": "edge", + "targetId": "crewEligibility" + }, + { + "id": "62052cad-4e0a-4e8c-8867-9481b608ebca", + "sourceId": "weightCalculations", + "type": "edge", + "targetId": "aircraftEligibility" + }, + { + "id": "1a2195e2-364c-4ba3-98ce-a64be30160ba", + "sourceId": "weightCalculations", + "type": "edge", + "targetId": "weatherEligibility" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/flight-rebooking-fee-calculator.json b/test-data/graphs/flight-rebooking-fee-calculator.json new file mode 100644 index 00000000..aca54f51 --- /dev/null +++ b/test-data/graphs/flight-rebooking-fee-calculator.json @@ -0,0 +1,406 @@ +{ + "tests": [ + { + "input": { + "bookingId": "BK-12345678", + "fareClass": "Economy", + "originalDepartureDate": "2025-05-15T10:30:00Z", + "newDepartureDate": "2025-05-20T14:15:00Z", + "daysToDeparture": 12, + "passengerDetails": { + "firstName": "Jane", + "lastName": "Smith", + "loyaltyTier": "Silver", + "loyaltyNumber": "LM789012" + }, + "changeFrequency": 2, + "loyaltyTier": "Silver" + }, + "output": { + "modificationFee": { + "allowed": true, + "description": "Standard modification fee", + "finalFee": 188 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "bookingModificationRequest", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'First'", + "i1-2": "> 14", + "o1-1": "0", + "o1-2": "'No fee for First Class with >14 days to departure'" + }, + { + "_id": "r1-2", + "i1-1": "'First'", + "i1-2": "<= 14", + "o1-1": "50", + "o1-2": "'Minimal fee for First Class with ≤14 days to departure'" + }, + { + "_id": "r1-3", + "i1-1": "'Business'", + "i1-2": "> 21", + "o1-1": "75", + "o1-2": "'Standard fee for Business Class with >21 days to departure'" + }, + { + "_id": "r1-4", + "i1-1": "'Business'", + "i1-2": "> 7 and <= 21", + "o1-1": "100", + "o1-2": "'Medium fee for Business Class with 7-21 days to departure'" + }, + { + "_id": "r1-5", + "i1-1": "'Business'", + "i1-2": "<= 7", + "o1-1": "150", + "o1-2": "'Higher fee for Business Class with ≤7 days to departure'" + }, + { + "_id": "r1-6", + "i1-1": "'Economy'", + "i1-2": "> 30", + "o1-1": "100", + "o1-2": "'Standard fee for Economy with >30 days to departure'" + }, + { + "_id": "r1-7", + "i1-1": "'Economy'", + "i1-2": "> 14 and <= 30", + "o1-1": "150", + "o1-2": "'Medium fee for Economy with 14-30 days to departure'" + }, + { + "_id": "r1-8", + "i1-1": "'Economy'", + "i1-2": "> 3 and <= 14", + "o1-1": "200", + "o1-2": "'High fee for Economy with 3-14 days to departure'" + }, + { + "_id": "r1-9", + "i1-1": "'Economy'", + "i1-2": "<= 3", + "o1-1": "250", + "o1-2": "'Very high fee for Economy with ≤3 days to departure'" + }, + { + "_id": "r1-10", + "i1-1": "", + "i1-2": "", + "o1-1": "300", + "o1-2": "'Default fee for any other fare class'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Fare Class", + "field": "fareClass" + }, + { + "id": "i1-2", + "name": "Days to Departure", + "field": "daysToDeparture" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Base Fee", + "field": "modificationFee.baseFee" + }, + { + "id": "o1-2", + "name": "Base Fee Reason", + "field": "modificationFee.baseFeeReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "baseFeeCalculation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "<= 1", + "o2-1": "1", + "o2-2": "'No additional charge for first change'" + }, + { + "_id": "r2-2", + "i2-1": "> 1 and <= 3", + "o2-1": "1.25", + "o2-2": "'25% surcharge for 2-3 changes'" + }, + { + "_id": "r2-3", + "i2-1": "> 3", + "o2-1": "1.5", + "o2-2": "'50% surcharge for frequent changes'" + }, + { + "_id": "r2-4", + "i2-1": "", + "o2-1": "1", + "o2-2": "'Default multiplier'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Change Frequency", + "field": "changeFrequency" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Frequency Multiplier", + "field": "modificationFee.frequencyMultiplier" + }, + { + "id": "o2-2", + "name": "Frequency Reason", + "field": "modificationFee.frequencyReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "frequencyMultiplier", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "'Platinum'", + "o3-1": "0", + "o3-2": "'Platinum members receive fee waiver'" + }, + { + "_id": "r3-2", + "i3-1": "'Gold'", + "o3-1": "0.5", + "o3-2": "'Gold members receive 50% discount'" + }, + { + "_id": "r3-3", + "i3-1": "'Silver'", + "o3-1": "0.75", + "o3-2": "'Silver members receive 25% discount'" + }, + { + "_id": "r3-4", + "i3-1": "", + "o3-1": "1", + "o3-2": "'No loyalty discount applied'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Loyalty Tier", + "field": "loyaltyTier" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Loyalty Factor", + "field": "modificationFee.loyaltyFactor" + }, + { + "id": "o3-2", + "name": "Loyalty Reason", + "field": "modificationFee.loyaltyReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt3", + "name": "loyaltyFactor", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "adjustedFee", + "value": "round(modificationFee.baseFee * modificationFee.frequencyMultiplier * modificationFee.loyaltyFactor)" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateAdjustedFee", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r4-1", + "i4-1": "loyaltyTier == 'Platinum' and daysToDeparture > 1", + "o4-1": "0", + "o4-2": "'Waived - Platinum member benefit'", + "o4-3": "true" + }, + { + "_id": "r4-2", + "i4-1": "adjustedFee == 0", + "o4-1": "0", + "o4-2": "'No fee applicable'", + "o4-3": "true" + }, + { + "_id": "r4-3", + "i4-1": "fareClass == 'First' and daysToDeparture <= 1", + "o4-1": "100", + "o4-2": "'Minimum fee for same-day changes'", + "o4-3": "true" + }, + { + "_id": "r4-4", + "i4-1": "daysToDeparture <= 1", + "o4-1": "max([200, adjustedFee])", + "o4-2": "'Same-day change fee applied'", + "o4-3": "true" + }, + { + "_id": "r4-5", + "i4-1": "", + "o4-1": "adjustedFee", + "o4-2": "'Standard modification fee'", + "o4-3": "true" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "Condition" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "Final Fee", + "field": "modificationFee.finalFee" + }, + { + "id": "o4-2", + "name": "Fee Description", + "field": "modificationFee.description" + }, + { + "id": "o4-3", + "name": "Modification Allowed", + "field": "modificationFee.allowed" + } + ], + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt4", + "name": "finalFeeAssessment", + "position": { + "x": 1710, + "y": 115 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt2", + "targetId": "dt3", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "dt3", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed5", + "sourceId": "ex1", + "targetId": "dt4", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/government-assistance.json b/test-data/graphs/government-assistance.json new file mode 100644 index 00000000..2da89a94 --- /dev/null +++ b/test-data/graphs/government-assistance.json @@ -0,0 +1,299 @@ +{ + "tests": [ + { + "input": { + "applicant": { + "annualIncome": 28000, + "householdSize": 3, + "age": 35, + "specialCircumstances": { + "hasDisability": true, + "isVeteran": false, + "isCaregiver": false + } + } + }, + "output": { + "applicant": { + "age": 35, + "annualIncome": 28000, + "householdSize": 3, + "specialCircumstances": { + "hasDisability": true, + "isCaregiver": false, + "isVeteran": false + } + }, + "eligibility": { + "assignedProgram": "full-assistance-enhanced", + "baseEligible": true, + "eligible": true, + "programType": "full-assistance" + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "income": "<= 15000", + "householdSize": "<= 2", + "age": ">= 18", + "baseEligibility": "true", + "programType": "'full-assistance'" + }, + { + "_id": "rule2", + "income": "<= 30000", + "householdSize": "> 2 and <= 4", + "age": ">= 18", + "baseEligibility": "true", + "programType": "'full-assistance'" + }, + { + "_id": "rule3", + "income": "<= 45000", + "householdSize": "> 4", + "age": ">= 18", + "baseEligibility": "true", + "programType": "'full-assistance'" + }, + { + "_id": "rule4", + "income": "> 15000 and <= 25000", + "householdSize": "<= 2", + "age": ">= 18", + "baseEligibility": "true", + "programType": "'partial-assistance'" + }, + { + "_id": "rule5", + "income": "> 30000 and <= 50000", + "householdSize": "> 2 and <= 4", + "age": ">= 18", + "baseEligibility": "true", + "programType": "'partial-assistance'" + }, + { + "_id": "rule6", + "income": "> 45000 and <= 65000", + "householdSize": "> 4", + "age": ">= 18", + "baseEligibility": "true", + "programType": "'partial-assistance'" + }, + { + "_id": "rule7", + "income": "<= 25000", + "householdSize": "", + "age": "< 18 and >= 16", + "baseEligibility": "true", + "programType": "'youth-assistance'" + }, + { + "_id": "rule8", + "income": "", + "householdSize": "", + "age": "", + "baseEligibility": "false", + "programType": "'ineligible'" + } + ], + "inputs": [ + { + "id": "income", + "name": "Annual Income", + "field": "applicant.annualIncome" + }, + { + "id": "householdSize", + "name": "Household Size", + "field": "applicant.householdSize" + }, + { + "id": "age", + "name": "Age", + "field": "applicant.age" + } + ], + "outputs": [ + { + "id": "baseEligibility", + "name": "Base Eligibility", + "field": "eligibility.baseEligible" + }, + { + "id": "programType", + "name": "Program Type", + "field": "eligibility.programType" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "incomeEligibility", + "name": "Income Eligibility", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "special1", + "baseEligibility": "false", + "hasDisability": "true", + "isVeteran": "", + "isCaregiver": "", + "finalEligibility": "true", + "bonusProgram": "'disability-support'" + }, + { + "_id": "special2", + "baseEligibility": "false", + "hasDisability": "", + "isVeteran": "true", + "isCaregiver": "", + "finalEligibility": "true", + "bonusProgram": "'veterans-assistance'" + }, + { + "_id": "special3", + "baseEligibility": "false", + "hasDisability": "", + "isVeteran": "", + "isCaregiver": "true", + "finalEligibility": "true", + "bonusProgram": "'caregiver-support'" + }, + { + "_id": "special4", + "baseEligibility": "true", + "hasDisability": "true", + "isVeteran": "", + "isCaregiver": "", + "finalEligibility": "true", + "bonusProgram": "eligibility.programType + '-enhanced'" + }, + { + "_id": "special5", + "baseEligibility": "true", + "hasDisability": "", + "isVeteran": "true", + "isCaregiver": "", + "finalEligibility": "true", + "bonusProgram": "eligibility.programType + '-enhanced'" + }, + { + "_id": "special6", + "baseEligibility": "true", + "hasDisability": "", + "isVeteran": "", + "isCaregiver": "true", + "finalEligibility": "true", + "bonusProgram": "eligibility.programType + '-caregiver'" + }, + { + "_id": "special7", + "baseEligibility": "true", + "hasDisability": "", + "isVeteran": "", + "isCaregiver": "", + "finalEligibility": "true", + "bonusProgram": "eligibility.programType" + }, + { + "_id": "special8", + "baseEligibility": "false", + "hasDisability": "", + "isVeteran": "", + "isCaregiver": "", + "finalEligibility": "false", + "bonusProgram": "'ineligible'" + } + ], + "inputs": [ + { + "id": "baseEligibility", + "name": "Base Eligibility", + "field": "eligibility.baseEligible" + }, + { + "id": "hasDisability", + "name": "Has Disability", + "field": "applicant.specialCircumstances.hasDisability" + }, + { + "id": "isVeteran", + "name": "Is Veteran", + "field": "applicant.specialCircumstances.isVeteran" + }, + { + "id": "isCaregiver", + "name": "Is Caregiver", + "field": "applicant.specialCircumstances.isCaregiver" + } + ], + "outputs": [ + { + "id": "finalEligibility", + "name": "Final Eligibility", + "field": "eligibility.eligible" + }, + { + "id": "bonusProgram", + "name": "Program Assignment", + "field": "eligibility.assignedProgram" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "specialCircumstances", + "name": "Special Circumstances", + "position": { + "x": 750, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "incomeEligibility", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "incomeEligibility", + "targetId": "specialCircumstances", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/grant-funding-distribution.json b/test-data/graphs/grant-funding-distribution.json new file mode 100644 index 00000000..34be87f7 --- /dev/null +++ b/test-data/graphs/grant-funding-distribution.json @@ -0,0 +1,307 @@ +{ + "tests": [ + { + "input": { + "application": { + "id": "GR-2025-0042", + "organizationName": "Community Health Initiative", + "projectTitle": "Rural Healthcare Access Program", + "projectScope": "high", + "applicantQualifications": "medium", + "requestedAmount": 75000, + "minimumViableAmount": 50000, + "impactMetrics": { + "beneficiaries": 1200, + "innovationScore": 72, + "sustainabilityScore": 68, + "communityNeedScore": 85, + "overallScore": 75 + } + }, + "budgetConstraints": { + "totalBudget": 500000, + "allocatedAmount": 325000, + "allocationRatio": 0.65, + "maxAwardAmount": 100000 + } + }, + "output": { + "fundingPercentage": 76, + "fundingStatus": "Approved", + "grantAmount": 57000, + "maxPossibleAmount": 57000 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "inputNode", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "'high'", + "i2": "'high'", + "i3": ">= 80", + "o1": "'high'", + "o2": "0.9" + }, + { + "_id": "r2", + "i1": "'high'", + "i2": "'medium'", + "i3": ">= 70", + "o1": "'high'", + "o2": "0.8" + }, + { + "_id": "r3", + "i1": "'medium'", + "i2": "'high'", + "i3": ">= 70", + "o1": "'high'", + "o2": "0.75" + }, + { + "_id": "r4", + "i1": "'high'", + "i2": "'low'", + "i3": ">= 60", + "o1": "'medium'", + "o2": "0.7" + }, + { + "_id": "r5", + "i1": "'medium'", + "i2": "'medium'", + "i3": ">= 60", + "o1": "'medium'", + "o2": "0.65" + }, + { + "_id": "r6", + "i1": "'low'", + "i2": "'high'", + "i3": ">= 60", + "o1": "'medium'", + "o2": "0.6" + }, + { + "_id": "r7", + "i1": "'medium'", + "i2": "'low'", + "i3": ">= 50", + "o1": "'low'", + "o2": "0.5" + }, + { + "_id": "r8", + "i1": "'low'", + "i2": "'medium'", + "i3": ">= 50", + "o1": "'low'", + "o2": "0.45" + }, + { + "_id": "r9", + "i1": "'low'", + "i2": "'low'", + "i3": ">= 40", + "o1": "'low'", + "o2": "0.4" + }, + { + "_id": "r10", + "i1": "", + "i2": "", + "i3": "", + "o1": "'rejected'", + "o2": "0" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Project Scope", + "field": "application.projectScope" + }, + { + "id": "i2", + "name": "Applicant Qualifications", + "field": "application.applicantQualifications" + }, + { + "id": "i3", + "name": "Impact Score", + "field": "application.impactMetrics.overallScore" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Funding Priority", + "field": "evaluation.fundingPriority" + }, + { + "id": "o2", + "name": "Base Funding Ratio", + "field": "evaluation.baseFundingRatio" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "projectEvaluation", + "name": "project_evaluation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "bc1", + "i1": "'high'", + "i2": "< 0.75", + "o1": "0.95" + }, + { + "_id": "bc2", + "i1": "'high'", + "i2": ">= 0.75", + "o1": "0.85" + }, + { + "_id": "bc3", + "i1": "'medium'", + "i2": "< 0.6", + "o1": "1.0" + }, + { + "_id": "bc4", + "i1": "'medium'", + "i2": ">= 0.6", + "o1": "0.9" + }, + { + "_id": "bc5", + "i1": "'low'", + "i2": "", + "o1": "1.0" + }, + { + "_id": "bc6", + "i1": "'rejected'", + "i2": "", + "o1": "0" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Funding Priority", + "field": "evaluation.fundingPriority" + }, + { + "id": "i2", + "name": "Budget Allocation Ratio", + "field": "budgetConstraints.allocationRatio" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Adjustment Factor", + "field": "evaluation.adjustmentFactor" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "budgetConstraint", + "name": "budget_constraint", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "fc1", + "key": "maxPossibleAmount", + "value": "application.requestedAmount * evaluation.baseFundingRatio * evaluation.adjustmentFactor" + }, + { + "id": "fc2", + "key": "grantAmount", + "value": "evaluation.fundingPriority == 'rejected' ? 0 : min([$.maxPossibleAmount, application.requestedAmount, budgetConstraints.maxAwardAmount])" + }, + { + "id": "fc3", + "key": "fundingStatus", + "value": "evaluation.fundingPriority == 'rejected' ? 'Rejected' : $.grantAmount >= application.minimumViableAmount ? 'Approved' : 'Partially Funded'" + }, + { + "id": "fc4", + "key": "fundingPercentage", + "value": "application.requestedAmount > 0 ? round($.grantAmount / application.requestedAmount * 100) : 0" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "fundingCalculation", + "name": "funding_calculation", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "inputNode", + "targetId": "projectEvaluation", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "projectEvaluation", + "targetId": "budgetConstraint", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "budgetConstraint", + "targetId": "fundingCalculation", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/hazardous-materials-management-system.json b/test-data/graphs/hazardous-materials-management-system.json new file mode 100644 index 00000000..213b8d60 --- /dev/null +++ b/test-data/graphs/hazardous-materials-management-system.json @@ -0,0 +1,414 @@ +{ + "tests": [ + { + "input": { + "material": "Sulfuric Acid", + "quantity": 75, + "state": "liquid", + "location": "Lab-B42", + "transportMode": "road" + }, + "output": { + "complianceRequirements": "Safety data sheets must accompany shipment", + "handlingProcedure": "Avoid contact with skin and eyes, neutralizing agents must be readily available", + "hazardClassification": "Class B - Corrosive", + "hazardLevel": "high", + "location": "Lab-B42", + "material": "Sulfuric Acid", + "permitRequired": "false", + "quantity": 75, + "recommendedStorageZone": "yellow-zone", + "reportingRequired": "false", + "requiredEquipment": "Chemical-resistant gloves, face shield, apron, boots", + "state": "liquid", + "storageLimit": 1000, + "transportMode": "road" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"material\": {\n \"type\": \"string\",\n \"description\": \"Name or code of hazardous material\"\n },\n \"quantity\": {\n \"type\": \"number\",\n \"description\": \"Quantity in kilograms\"\n },\n \"state\": {\n \"type\": \"string\",\n \"enum\": [\"solid\", \"liquid\", \"gas\"],\n \"description\": \"Physical state of the material\"\n },\n \"location\": {\n \"type\": \"string\",\n \"description\": \"Storage or handling location code\"\n },\n \"transportMode\": {\n \"type\": \"string\",\n \"enum\": [\"road\", \"rail\", \"air\", \"sea\", \"internal\"],\n \"description\": \"Mode of transportation if applicable\"\n }\n },\n \"required\": [\"material\", \"quantity\", \"state\"]\n}\n" + }, + "id": "inputNode", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "materialType": "some(['flammable', 'combustible'], contains($, #))", + "materialState": "'liquid', 'gas'", + "materialQuantity": "", + "classificationOutput": "'Class A - Flammable'", + "hazardLevelOutput": "'high'", + "storageZoneOutput": "'red-zone'" + }, + { + "_id": "rule2", + "materialType": "some(['corrosive', 'acid', 'base'], contains($, #))", + "materialState": "", + "materialQuantity": "", + "classificationOutput": "'Class B - Corrosive'", + "hazardLevelOutput": "'high'", + "storageZoneOutput": "'yellow-zone'" + }, + { + "_id": "rule3", + "materialType": "some(['toxic', 'poison'], contains($, #))", + "materialState": "", + "materialQuantity": "> 25", + "classificationOutput": "'Class C - Toxic'", + "hazardLevelOutput": "'high'", + "storageZoneOutput": "'green-zone'" + }, + { + "_id": "rule4", + "materialType": "some(['toxic', 'poison'], contains($, #))", + "materialState": "", + "materialQuantity": "<= 25", + "classificationOutput": "'Class C - Toxic'", + "hazardLevelOutput": "'medium'", + "storageZoneOutput": "'green-zone'" + }, + { + "_id": "rule5", + "materialType": "some(['radioactive'], contains($, #))", + "materialState": "", + "materialQuantity": "", + "classificationOutput": "'Class D - Radioactive'", + "hazardLevelOutput": "'extreme'", + "storageZoneOutput": "'black-zone'" + }, + { + "_id": "rule6", + "materialType": "some(['explosive'], contains($, #))", + "materialState": "", + "materialQuantity": "", + "classificationOutput": "'Class E - Explosive'", + "hazardLevelOutput": "'extreme'", + "storageZoneOutput": "'black-zone'" + }, + { + "_id": "rule7", + "materialType": "some(['oxidizer', 'oxidizing'], contains($, #))", + "materialState": "", + "materialQuantity": "", + "classificationOutput": "'Class F - Oxidizer'", + "hazardLevelOutput": "'high'", + "storageZoneOutput": "'blue-zone'" + }, + { + "_id": "rule8", + "materialType": "", + "materialState": "", + "materialQuantity": "", + "classificationOutput": "'Unclassified'", + "hazardLevelOutput": "'low'", + "storageZoneOutput": "'grey-zone'" + } + ], + "inputs": [ + { + "id": "materialType", + "name": "Material Type", + "field": "lower(material)" + }, + { + "id": "materialState", + "name": "State", + "field": "state" + }, + { + "id": "materialQuantity", + "name": "Quantity (kg)", + "field": "quantity" + } + ], + "outputs": [ + { + "id": "classificationOutput", + "name": "Classification", + "field": "hazardClassification" + }, + { + "id": "hazardLevelOutput", + "name": "Hazard Level", + "field": "hazardLevel" + }, + { + "id": "storageZoneOutput", + "name": "Storage Zone", + "field": "recommendedStorageZone" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "materialClassificationTable", + "name": "Material Classification", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "hazardClass": "'Class A - Flammable'", + "hazardLevel": "'high'", + "handlingEquipmentOutput": "'Fire-resistant gloves, face shield, flame-retardant clothing'", + "handlingProcedureOutput": "'Keep away from ignition sources, ensure proper ventilation, use non-sparking tools'", + "storageLimitOutput": "500" + }, + { + "_id": "rule2", + "hazardClass": "'Class B - Corrosive'", + "hazardLevel": "'high'", + "handlingEquipmentOutput": "'Chemical-resistant gloves, face shield, apron, boots'", + "handlingProcedureOutput": "'Avoid contact with skin and eyes, neutralizing agents must be readily available'", + "storageLimitOutput": "1000" + }, + { + "_id": "rule3", + "hazardClass": "'Class C - Toxic'", + "hazardLevel": "'high'", + "handlingEquipmentOutput": "'Chemical-resistant gloves, respirator, full protective suit'", + "handlingProcedureOutput": "'Use only in designated areas with proper ventilation, decontamination station required'", + "storageLimitOutput": "250" + }, + { + "_id": "rule4", + "hazardClass": "'Class C - Toxic'", + "hazardLevel": "'medium'", + "handlingEquipmentOutput": "'Chemical-resistant gloves, safety goggles, lab coat'", + "handlingProcedureOutput": "'Use in well-ventilated area, wash hands thoroughly after handling'", + "storageLimitOutput": "500" + }, + { + "_id": "rule5", + "hazardClass": "'Class D - Radioactive'", + "hazardLevel": "'extreme'", + "handlingEquipmentOutput": "'Radiation suit, dosimeter, remote handling tools'", + "handlingProcedureOutput": "'Special authorization required, time and distance protocols, radiation monitoring mandatory'", + "storageLimitOutput": "50" + }, + { + "_id": "rule6", + "hazardClass": "'Class E - Explosive'", + "hazardLevel": "'extreme'", + "handlingEquipmentOutput": "'Anti-static clothing, specialized tools, blast shield'", + "handlingProcedureOutput": "'Expert personnel only, evacuation plan required, no electronic devices'", + "storageLimitOutput": "100" + }, + { + "_id": "rule7", + "hazardClass": "'Class F - Oxidizer'", + "hazardLevel": "'high'", + "handlingEquipmentOutput": "'Chemical-resistant gloves, safety goggles, lab coat'", + "handlingProcedureOutput": "'Keep away from combustible materials, avoid contamination'", + "storageLimitOutput": "750" + }, + { + "_id": "rule8", + "hazardClass": "'Unclassified'", + "hazardLevel": "'low'", + "handlingEquipmentOutput": "'Standard PPE (gloves, safety glasses)'", + "handlingProcedureOutput": "'Follow general laboratory safety procedures'", + "storageLimitOutput": "2000" + } + ], + "inputs": [ + { + "id": "hazardClass", + "name": "Hazard Classification", + "field": "hazardClassification" + }, + { + "id": "hazardLevel", + "name": "Hazard Level", + "field": "hazardLevel" + } + ], + "outputs": [ + { + "id": "handlingEquipmentOutput", + "name": "Required Equipment", + "field": "requiredEquipment" + }, + { + "id": "handlingProcedureOutput", + "name": "Handling Procedure", + "field": "handlingProcedure" + }, + { + "id": "storageLimitOutput", + "name": "Storage Limit (kg)", + "field": "storageLimit" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "handlingRequirementsTable", + "name": "Handling Requirements", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "hazardClass": "'Class A - Flammable', 'Class E - Explosive'", + "transportMode": "'air'", + "quantityCheck": "> 5", + "complianceOutput": "'Prohibited for air transport in this quantity'", + "permitRequiredOutput": "'true'", + "reportingRequiredOutput": "'true'" + }, + { + "_id": "rule2", + "hazardClass": "'Class D - Radioactive'", + "transportMode": "'road', 'rail', 'air', 'sea'", + "quantityCheck": "", + "complianceOutput": "'Special NRC permit required, scheduled route mandatory'", + "permitRequiredOutput": "'true'", + "reportingRequiredOutput": "'true'" + }, + { + "_id": "rule3", + "hazardClass": "'Class A - Flammable', 'Class B - Corrosive', 'Class C - Toxic', 'Class F - Oxidizer'", + "transportMode": "'road', 'rail', 'sea'", + "quantityCheck": "> 1000", + "complianceOutput": "'HAZMAT placards required, certified driver/handler only'", + "permitRequiredOutput": "'true'", + "reportingRequiredOutput": "'true'" + }, + { + "_id": "rule4", + "hazardClass": "'Class A - Flammable', 'Class B - Corrosive', 'Class C - Toxic', 'Class F - Oxidizer'", + "transportMode": "'road', 'rail', 'sea'", + "quantityCheck": "> 100 and <= 1000", + "complianceOutput": "'HAZMAT placards required, safety data sheets must accompany shipment'", + "permitRequiredOutput": "'true'", + "reportingRequiredOutput": "'false'" + }, + { + "_id": "rule5", + "hazardClass": "'Class A - Flammable', 'Class B - Corrosive', 'Class C - Toxic', 'Class F - Oxidizer'", + "transportMode": "'road', 'rail', 'sea'", + "quantityCheck": "<= 100", + "complianceOutput": "'Safety data sheets must accompany shipment'", + "permitRequiredOutput": "'false'", + "reportingRequiredOutput": "'false'" + }, + { + "_id": "rule6", + "hazardClass": "'Class A - Flammable', 'Class B - Corrosive', 'Class C - Toxic', 'Class F - Oxidizer'", + "transportMode": "'internal'", + "quantityCheck": "", + "complianceOutput": "'Internal movement log required'", + "permitRequiredOutput": "'false'", + "reportingRequiredOutput": "'false'" + }, + { + "_id": "rule7", + "hazardClass": "'Unclassified'", + "transportMode": "", + "quantityCheck": "", + "complianceOutput": "'Standard shipping procedures apply'", + "permitRequiredOutput": "'false'", + "reportingRequiredOutput": "'false'" + } + ], + "inputs": [ + { + "id": "hazardClass", + "name": "Hazard Classification", + "field": "hazardClassification" + }, + { + "id": "transportMode", + "name": "Transport Mode", + "field": "transportMode" + }, + { + "id": "quantityCheck", + "name": "Quantity (kg)", + "field": "quantity" + } + ], + "outputs": [ + { + "id": "complianceOutput", + "name": "Compliance Requirements", + "field": "complianceRequirements" + }, + { + "id": "permitRequiredOutput", + "name": "Permit Required", + "field": "permitRequired" + }, + { + "id": "reportingRequiredOutput", + "name": "Reporting Required", + "field": "reportingRequired" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "regulatoryComplianceTable", + "name": "Regulatory Compliance", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "inputNode", + "targetId": "materialClassificationTable", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "materialClassificationTable", + "targetId": "handlingRequirementsTable", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "handlingRequirementsTable", + "targetId": "regulatoryComplianceTable", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/immigration-eligibility-evaluator.json b/test-data/graphs/immigration-eligibility-evaluator.json new file mode 100644 index 00000000..335c1740 --- /dev/null +++ b/test-data/graphs/immigration-eligibility-evaluator.json @@ -0,0 +1,765 @@ +{ + "tests": [ + { + "input": { + "applicant": { + "fullName": "Jane Smith", + "dateOfBirth": "1985-05-15", + "nationality": "United Kingdom", + "currentResidence": "France" + }, + "documentation": { + "passportValid": true, + "visaApplicationComplete": true, + "proofOfFundsProvided": true, + "medicalCheckComplete": true, + "supportingDocuments": [ + "Reference Letter", + "Property Deed", + "Bank Statements" + ] + }, + "background": { + "criminalHistory": false, + "immigrationViolations": false, + "securityConcerns": false, + "previousVisaRejections": 0 + }, + "qualifications": { + "educationLevel": "master", + "workExperienceYears": 8, + "languageProficiency": "advanced", + "skillsInDemand": true, + "familyConnections": false + } + }, + "output": { + "applicant": { + "currentResidence": "France", + "dateOfBirth": "1985-05-15", + "fullName": "Jane Smith", + "nationality": "United Kingdom" + }, + "assessment": { + "additionalFactorsReason": "In-demand skills", + "additionalFactorsScore": 80, + "backgroundReason": "Background check clear", + "backgroundScore": 100, + "backgroundStatus": "pending", + "documentationReason": "Documentation complete", + "documentationScore": 100, + "documentationStatus": "pending", + "educationReason": "Advanced education", + "educationScore": 80, + "experienceReason": "Significant work experience", + "experienceScore": 80, + "finalReason": "Application meets criteria", + "finalStatus": "approved", + "languageReason": "Advanced language proficiency", + "languageScore": 75, + "overallScore": 85.83333333333333 + }, + "background": { + "criminalHistory": false, + "immigrationViolations": false, + "previousVisaRejections": 0, + "securityConcerns": false + }, + "documentation": { + "medicalCheckComplete": true, + "passportValid": true, + "proofOfFundsProvided": true, + "supportingDocuments": [ + "Reference Letter", + "Property Deed", + "Bank Statements" + ], + "visaApplicationComplete": true + }, + "qualifications": { + "educationLevel": "master", + "familyConnections": false, + "languageProficiency": "advanced", + "skillsInDemand": true, + "workExperienceYears": 8 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"applicant\": {\n \"type\": \"object\",\n \"properties\": {\n \"fullName\": {\"type\": \"string\"},\n \"dateOfBirth\": {\"type\": \"string\"},\n \"nationality\": {\"type\": \"string\"},\n \"currentResidence\": {\"type\": \"string\"}\n }\n },\n \"documentation\": {\n \"type\": \"object\",\n \"properties\": {\n \"passportValid\": {\"type\": \"boolean\"},\n \"visaApplicationComplete\": {\"type\": \"boolean\"},\n \"proofOfFundsProvided\": {\"type\": \"boolean\"},\n \"medicalCheckComplete\": {\"type\": \"boolean\"},\n \"supportingDocuments\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n }\n },\n \"background\": {\n \"type\": \"object\",\n \"properties\": {\n \"criminalHistory\": {\"type\": \"boolean\"},\n \"immigrationViolations\": {\"type\": \"boolean\"},\n \"securityConcerns\": {\"type\": \"boolean\"},\n \"previousVisaRejections\": {\"type\": \"integer\", \"minimum\": 0}\n }\n },\n \"qualifications\": {\n \"type\": \"object\",\n \"properties\": {\n \"educationLevel\": {\"type\": \"string\", \"enum\": [\"none\", \"primary\", \"secondary\", \"bachelor\", \"master\", \"doctorate\"]},\n \"workExperienceYears\": {\"type\": \"integer\", \"minimum\": 0},\n \"languageProficiency\": {\"type\": \"string\", \"enum\": [\"none\", \"basic\", \"intermediate\", \"advanced\", \"native\"]},\n \"skillsInDemand\": {\"type\": \"boolean\"},\n \"familyConnections\": {\"type\": \"boolean\"}\n }\n }\n }\n}" + }, + "id": "input", + "name": "immigrationApplication", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1-1": "false", + "i1-2": "", + "i1-3": "", + "i1-4": "", + "o1-1": "\"rejected\"", + "o1-2": "\"Missing valid passport\"", + "o1-3": "0" + }, + { + "_id": "rule2", + "i1-1": "", + "i1-2": "false", + "i1-3": "", + "i1-4": "", + "o1-1": "\"incomplete\"", + "o1-2": "\"Incomplete visa application\"", + "o1-3": "40" + }, + { + "_id": "rule3", + "i1-1": "", + "i1-2": "", + "i1-3": "false", + "i1-4": "", + "o1-1": "\"incomplete\"", + "o1-2": "\"Missing proof of funds\"", + "o1-3": "50" + }, + { + "_id": "rule4", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "i1-4": "false", + "o1-1": "\"incomplete\"", + "o1-2": "\"Medical check not completed\"", + "o1-3": "60" + }, + { + "_id": "rule5", + "i1-1": "true", + "i1-2": "true", + "i1-3": "true", + "i1-4": "true", + "o1-1": "\"pending\"", + "o1-2": "\"Documentation complete\"", + "o1-3": "100" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Passport Valid", + "field": "documentation.passportValid" + }, + { + "id": "i1-2", + "name": "Application Complete", + "field": "documentation.visaApplicationComplete" + }, + { + "id": "i1-3", + "name": "Proof of Funds", + "field": "documentation.proofOfFundsProvided" + }, + { + "id": "i1-4", + "name": "Medical Check", + "field": "documentation.medicalCheckComplete" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Status", + "field": "assessment.documentationStatus" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "assessment.documentationReason" + }, + { + "id": "o1-3", + "name": "Score", + "field": "assessment.documentationScore" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "documentationCheck", + "name": "verifyDocumentation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i2-1": "true", + "i2-2": "", + "i2-3": "", + "i2-4": "", + "o2-1": "\"rejected\"", + "o2-2": "\"Criminal history detected\"", + "o2-3": "0" + }, + { + "_id": "rule2", + "i2-1": "false", + "i2-2": "true", + "i2-3": "", + "i2-4": "", + "o2-1": "\"review\"", + "o2-2": "\"Immigration violations\"", + "o2-3": "30" + }, + { + "_id": "rule3", + "i2-1": "false", + "i2-2": "false", + "i2-3": "true", + "i2-4": "", + "o2-1": "\"review\"", + "o2-2": "\"Security concerns\"", + "o2-3": "20" + }, + { + "_id": "rule4", + "i2-1": "false", + "i2-2": "false", + "i2-3": "false", + "i2-4": ">= 3", + "o2-1": "\"review\"", + "o2-2": "\"Multiple previous rejections\"", + "o2-3": "40" + }, + { + "_id": "rule5", + "i2-1": "false", + "i2-2": "false", + "i2-3": "false", + "i2-4": "1, 2", + "o2-1": "\"pending\"", + "o2-2": "\"Previous rejections noted\"", + "o2-3": "70" + }, + { + "_id": "rule6", + "i2-1": "false", + "i2-2": "false", + "i2-3": "false", + "i2-4": "0", + "o2-1": "\"pending\"", + "o2-2": "\"Background check clear\"", + "o2-3": "100" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Criminal History", + "field": "background.criminalHistory" + }, + { + "id": "i2-2", + "name": "Immigration Violations", + "field": "background.immigrationViolations" + }, + { + "id": "i2-3", + "name": "Security Concerns", + "field": "background.securityConcerns" + }, + { + "id": "i2-4", + "name": "Previous Rejections", + "field": "background.previousVisaRejections" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Status", + "field": "assessment.backgroundStatus" + }, + { + "id": "o2-2", + "name": "Reason", + "field": "assessment.backgroundReason" + }, + { + "id": "o2-3", + "name": "Score", + "field": "assessment.backgroundScore" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "backgroundCheck", + "name": "evaluateBackground", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i3-1": "\"doctorate\"", + "o3-1": "100", + "o3-2": "\"Highest education level\"" + }, + { + "_id": "rule2", + "i3-1": "\"master\"", + "o3-1": "80", + "o3-2": "\"Advanced education\"" + }, + { + "_id": "rule3", + "i3-1": "\"bachelor\"", + "o3-1": "60", + "o3-2": "\"University education\"" + }, + { + "_id": "rule4", + "i3-1": "\"secondary\"", + "o3-1": "40", + "o3-2": "\"Secondary education\"" + }, + { + "_id": "rule5", + "i3-1": "\"primary\"", + "o3-1": "20", + "o3-2": "\"Primary education only\"" + }, + { + "_id": "rule6", + "i3-1": "\"none\"", + "o3-1": "0", + "o3-2": "\"No formal education\"" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Education Level", + "field": "qualifications.educationLevel" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Score", + "field": "assessment.educationScore" + }, + { + "id": "o3-2", + "name": "Reason", + "field": "assessment.educationReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "educationTable", + "name": "assessEducation", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i4-1": ">= 10", + "o4-1": "100", + "o4-2": "\"Extensive work experience\"" + }, + { + "_id": "rule2", + "i4-1": ">= 7", + "o4-1": "80", + "o4-2": "\"Significant work experience\"" + }, + { + "_id": "rule3", + "i4-1": ">= 4", + "o4-1": "60", + "o4-2": "\"Moderate work experience\"" + }, + { + "_id": "rule4", + "i4-1": ">= 2", + "o4-1": "40", + "o4-2": "\"Limited work experience\"" + }, + { + "_id": "rule5", + "i4-1": ">= 1", + "o4-1": "20", + "o4-2": "\"Minimal work experience\"" + }, + { + "_id": "rule6", + "i4-1": "0", + "o4-1": "0", + "o4-2": "\"No work experience\"" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "Work Experience Years", + "field": "qualifications.workExperienceYears" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "Score", + "field": "assessment.experienceScore" + }, + { + "id": "o4-2", + "name": "Reason", + "field": "assessment.experienceReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "experienceTable", + "name": "assessWorkExperience", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i5-1": "\"native\"", + "o5-1": "100", + "o5-2": "\"Native language proficiency\"" + }, + { + "_id": "rule2", + "i5-1": "\"advanced\"", + "o5-1": "75", + "o5-2": "\"Advanced language proficiency\"" + }, + { + "_id": "rule3", + "i5-1": "\"intermediate\"", + "o5-1": "50", + "o5-2": "\"Intermediate language proficiency\"" + }, + { + "_id": "rule4", + "i5-1": "\"basic\"", + "o5-1": "25", + "o5-2": "\"Basic language proficiency\"" + }, + { + "_id": "rule5", + "i5-1": "\"none\"", + "o5-1": "0", + "o5-2": "\"No language proficiency\"" + } + ], + "inputs": [ + { + "id": "i5-1", + "name": "Language Proficiency", + "field": "qualifications.languageProficiency" + } + ], + "outputs": [ + { + "id": "o5-1", + "name": "Score", + "field": "assessment.languageScore" + }, + { + "id": "o5-2", + "name": "Reason", + "field": "assessment.languageReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "languageTable", + "name": "assessLanguage", + "position": { + "x": 1710, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i6-1": "true", + "i6-2": "true", + "o6-1": "100", + "o6-2": "\"In-demand skills and family connections\"" + }, + { + "_id": "rule2", + "i6-1": "true", + "i6-2": "false", + "o6-1": "80", + "o6-2": "\"In-demand skills\"" + }, + { + "_id": "rule3", + "i6-1": "false", + "i6-2": "true", + "o6-1": "70", + "o6-2": "\"Family connections\"" + }, + { + "_id": "rule4", + "i6-1": "false", + "i6-2": "false", + "o6-1": "0", + "o6-2": "\"No additional qualifying factors\"" + } + ], + "inputs": [ + { + "id": "i6-1", + "name": "Skills In Demand", + "field": "qualifications.skillsInDemand" + }, + { + "id": "i6-2", + "name": "Family Connections", + "field": "qualifications.familyConnections" + } + ], + "outputs": [ + { + "id": "o6-1", + "name": "Score", + "field": "assessment.additionalFactorsScore" + }, + { + "id": "o6-2", + "name": "Reason", + "field": "assessment.additionalFactorsReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "additionalFactorsTable", + "name": "assessAdditionalFactors", + "position": { + "x": 2030, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i7-1": "\"rejected\"", + "i7-2": "", + "o7-1": "\"rejected\"", + "o7-2": "assessment.documentationReason", + "o7-3": "assessment.documentationScore" + }, + { + "_id": "rule2", + "i7-1": "", + "i7-2": "\"rejected\"", + "o7-1": "\"rejected\"", + "o7-2": "assessment.backgroundReason", + "o7-3": "assessment.backgroundScore" + }, + { + "_id": "rule3", + "i7-1": "\"incomplete\"", + "i7-2": "", + "o7-1": "\"incomplete\"", + "o7-2": "assessment.documentationReason", + "o7-3": "assessment.documentationScore" + }, + { + "_id": "rule4", + "i7-1": "", + "i7-2": "\"review\"", + "o7-1": "\"review\"", + "o7-2": "assessment.backgroundReason", + "o7-3": "(assessment.documentationScore + assessment.backgroundScore + assessment.educationScore + assessment.experienceScore + assessment.languageScore + assessment.additionalFactorsScore) / 6" + }, + { + "_id": "rule5", + "i7-1": "", + "i7-2": "", + "i7-3": ">= 70", + "o7-1": "\"approved\"", + "o7-2": "\"Application meets criteria\"", + "o7-3": "(assessment.documentationScore + assessment.backgroundScore + assessment.educationScore + assessment.experienceScore + assessment.languageScore + assessment.additionalFactorsScore) / 6" + }, + { + "_id": "rule6", + "i7-1": "", + "i7-2": "", + "i7-3": ">= 50", + "o7-1": "\"review\"", + "o7-2": "\"Application requires further review\"", + "o7-3": "(assessment.documentationScore + assessment.backgroundScore + assessment.educationScore + assessment.experienceScore + assessment.languageScore + assessment.additionalFactorsScore) / 6" + }, + { + "_id": "rule7", + "i7-1": "", + "i7-2": "", + "i7-3": "", + "o7-1": "\"rejected\"", + "o7-2": "\"Application does not meet minimum requirements\"", + "o7-3": "(assessment.documentationScore + assessment.backgroundScore + assessment.educationScore + assessment.experienceScore + assessment.languageScore + assessment.additionalFactorsScore) / 6" + } + ], + "inputs": [ + { + "id": "i7-1", + "name": "Documentation Status", + "field": "assessment.documentationStatus" + }, + { + "id": "i7-2", + "name": "Background Status", + "field": "assessment.backgroundStatus" + }, + { + "id": "i7-3", + "name": "Average Score", + "field": "(assessment.documentationScore + assessment.backgroundScore + assessment.educationScore + assessment.experienceScore + assessment.languageScore + assessment.additionalFactorsScore) / 6" + } + ], + "outputs": [ + { + "id": "o7-1", + "name": "Final Status", + "field": "assessment.finalStatus" + }, + { + "id": "o7-2", + "name": "Final Reason", + "field": "assessment.finalReason" + }, + { + "id": "o7-3", + "name": "Overall Score", + "field": "assessment.overallScore" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "overallAssessment", + "name": "finalAssessment", + "position": { + "x": 2350, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "documentationCheck", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "documentationCheck", + "targetId": "backgroundCheck", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "backgroundCheck", + "targetId": "educationTable", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "educationTable", + "targetId": "experienceTable", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "experienceTable", + "targetId": "languageTable", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "languageTable", + "targetId": "additionalFactorsTable", + "type": "edge" + }, + { + "id": "edge7", + "sourceId": "additionalFactorsTable", + "targetId": "overallAssessment", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/import-duties-calculator.json b/test-data/graphs/import-duties-calculator.json new file mode 100644 index 00000000..73cb63bf --- /dev/null +++ b/test-data/graphs/import-duties-calculator.json @@ -0,0 +1,318 @@ +{ + "tests": [ + { + "input": { + "product": { + "category": "electronics", + "value": 1200, + "weight": 0.8, + "hsCode": "851712" + }, + "origin": { + "country": "CN", + "hasFTA": false, + "preferentialTreatment": false + }, + "destination": { + "country": "US" + } + }, + "output": { + "additionalFees": 0, + "baseDuty": 180, + "countryAdjustment": 225, + "dutyRate": 0.1875, + "minDuty": 225, + "preferentialDiscount": 225, + "totalDuty": 225 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"product\": {\n \"type\": \"object\",\n \"properties\": {\n \"category\": {\n \"type\": \"string\",\n \"description\": \"Product category\"\n },\n \"value\": {\n \"type\": \"number\",\n \"description\": \"Product value in USD\"\n },\n \"weight\": {\n \"type\": \"number\",\n \"description\": \"Product weight in kg\"\n },\n \"hsCode\": {\n \"type\": \"string\",\n \"description\": \"Harmonized System code\"\n }\n }\n },\n \"origin\": {\n \"type\": \"object\",\n \"properties\": {\n \"country\": {\n \"type\": \"string\",\n \"description\": \"Country of origin\"\n },\n \"hasFTA\": {\n \"type\": \"boolean\",\n \"description\": \"Has free trade agreement\"\n },\n \"preferentialTreatment\": {\n \"type\": \"boolean\",\n \"description\": \"Eligible for preferential treatment\"\n }\n }\n },\n \"destination\": {\n \"type\": \"object\",\n \"properties\": {\n \"country\": {\n \"type\": \"string\",\n \"description\": \"Destination country\"\n }\n }\n }\n }\n}" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "pc-1", + "i-category": "'electronics'", + "i-hsCode": "startsWith($, '85')", + "o-baseRate": "0.15", + "o-category": "'High-Tech Electronics'" + }, + { + "_id": "pc-2", + "i-category": "'electronics'", + "i-hsCode": "startsWith($, '90')", + "o-baseRate": "0.12", + "o-category": "'Precision Electronics'" + }, + { + "_id": "pc-3", + "i-category": "'textiles'", + "i-hsCode": "startsWith($, '61'), startsWith($, '62')", + "o-baseRate": "0.20", + "o-category": "'Clothing'" + }, + { + "_id": "pc-4", + "i-category": "'textiles'", + "i-hsCode": "startsWith($, '63')", + "o-baseRate": "0.18", + "o-category": "'Home Textiles'" + }, + { + "_id": "pc-5", + "i-category": "'food'", + "i-hsCode": "startsWith($, '02'), startsWith($, '03'), startsWith($, '04')", + "o-baseRate": "0.22", + "o-category": "'Perishable Food'" + }, + { + "_id": "pc-6", + "i-category": "'food'", + "i-hsCode": "startsWith($, '19'), startsWith($, '20'), startsWith($, '21')", + "o-baseRate": "0.16", + "o-category": "'Processed Food'" + }, + { + "_id": "pc-7", + "i-category": "'automotive'", + "i-hsCode": "startsWith($, '87')", + "o-baseRate": "0.25", + "o-category": "'Vehicles'" + }, + { + "_id": "pc-8", + "i-category": "", + "i-hsCode": "", + "o-baseRate": "0.18", + "o-category": "'General Merchandise'" + } + ], + "inputs": [ + { + "id": "i-category", + "name": "Product Category", + "field": "product.category" + }, + { + "id": "i-hsCode", + "name": "HS Code", + "field": "product.hsCode" + } + ], + "outputs": [ + { + "id": "o-baseRate", + "name": "Base Duty Rate", + "field": "classification.baseRate" + }, + { + "id": "o-category", + "name": "Product Classification", + "field": "classification.category" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "product_classification", + "name": "product_classification", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "cr-1", + "i-origin": "'CN'", + "i-destination": "'US'", + "i-hasFTA": "false", + "o-countryMultiplier": "1.25", + "o-hasSanctions": "false" + }, + { + "_id": "cr-2", + "i-origin": "'MX'", + "i-destination": "'US'", + "i-hasFTA": "true", + "o-countryMultiplier": "0.0", + "o-hasSanctions": "false" + }, + { + "_id": "cr-3", + "i-origin": "'CA'", + "i-destination": "'US'", + "i-hasFTA": "true", + "o-countryMultiplier": "0.0", + "o-hasSanctions": "false" + }, + { + "_id": "cr-4", + "i-origin": "'GB', 'DE', 'FR', 'IT', 'ES'", + "i-destination": "'US'", + "i-hasFTA": "false", + "o-countryMultiplier": "0.8", + "o-hasSanctions": "false" + }, + { + "_id": "cr-5", + "i-origin": "'KP', 'IR'", + "i-destination": "'US'", + "i-hasFTA": "", + "o-countryMultiplier": "3.0", + "o-hasSanctions": "true" + }, + { + "_id": "cr-6", + "i-origin": "'VN'", + "i-destination": "'US'", + "i-hasFTA": "false", + "o-countryMultiplier": "0.9", + "o-hasSanctions": "false" + }, + { + "_id": "cr-7", + "i-origin": "", + "i-destination": "", + "i-hasFTA": "", + "o-countryMultiplier": "1.0", + "o-hasSanctions": "false" + } + ], + "inputs": [ + { + "id": "i-origin", + "name": "Origin Country", + "field": "origin.country" + }, + { + "id": "i-destination", + "name": "Destination Country", + "field": "destination.country" + }, + { + "id": "i-hasFTA", + "name": "Has FTA", + "field": "origin.hasFTA" + } + ], + "outputs": [ + { + "id": "o-countryMultiplier", + "name": "Country Multiplier", + "field": "countryRules.multiplier" + }, + { + "id": "o-hasSanctions", + "name": "Has Sanctions", + "field": "countryRules.hasSanctions" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "country_rules", + "name": "country_rules", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "baseDuty", + "value": "product.value * number(classification.baseRate)" + }, + { + "id": "expr2", + "key": "countryAdjustment", + "value": "$.baseDuty * number(countryRules.multiplier)" + }, + { + "id": "expr3", + "key": "additionalFees", + "value": "countryRules.hasSanctions == true ? product.value * 0.1 : 0" + }, + { + "id": "expr4", + "key": "preferentialDiscount", + "value": "origin.preferentialTreatment == true ? $.countryAdjustment * 0.8 : $.countryAdjustment" + }, + { + "id": "expr5", + "key": "minDuty", + "value": "$.countryAdjustment > 0 ? max([10, $.preferentialDiscount]) : 0" + }, + { + "id": "expr6", + "key": "totalDuty", + "value": "$.minDuty + $.additionalFees" + }, + { + "id": "expr7", + "key": "dutyRate", + "value": "$.totalDuty / product.value" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "duty_calculation", + "name": "duty_calculation", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "product_classification", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "product_classification", + "targetId": "country_rules", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "country_rules", + "targetId": "duty_calculation", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/insurance-agent-commission.json b/test-data/graphs/insurance-agent-commission.json new file mode 100644 index 00000000..7851b78f --- /dev/null +++ b/test-data/graphs/insurance-agent-commission.json @@ -0,0 +1,228 @@ +{ + "tests": [ + { + "input": { + "policyType": "home", + "premiumAmount": 2000, + "performanceTier": "gold" + }, + "output": { + "baseCommission": 360, + "baseCommissionRate": 0.18, + "finalCommission": 450, + "performanceTier": "gold", + "policyType": "home", + "premiumAmount": 2000, + "tierMultiplier": 1.25 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'auto'", + "i1-2": "> 2000", + "o1-1": "0.15" + }, + { + "_id": "r1-2", + "i1-1": "'auto'", + "i1-2": "> 1000", + "o1-1": "0.12" + }, + { + "_id": "r1-3", + "i1-1": "'auto'", + "i1-2": "", + "o1-1": "0.10" + }, + { + "_id": "r1-4", + "i1-1": "'home'", + "i1-2": "> 1500", + "o1-1": "0.18" + }, + { + "_id": "r1-5", + "i1-1": "'home'", + "i1-2": "", + "o1-1": "0.15" + }, + { + "_id": "r1-6", + "i1-1": "'life'", + "i1-2": "> 5000", + "o1-1": "0.25" + }, + { + "_id": "r1-7", + "i1-1": "'life'", + "i1-2": "> 2500", + "o1-1": "0.22" + }, + { + "_id": "r1-8", + "i1-1": "'life'", + "i1-2": "", + "o1-1": "0.20" + }, + { + "_id": "r1-9", + "i1-1": "", + "i1-2": "", + "o1-1": "0.08" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Policy Type", + "field": "policyType" + }, + { + "id": "i1-2", + "name": "Premium Amount", + "field": "premiumAmount" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Base Commission Rate", + "field": "baseCommissionRate" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "baseCommissionRates", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "baseCommission", + "value": "premiumAmount * baseCommissionRate" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateBaseCommission", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'platinum'", + "o2-1": "1.5", + "o2-2": "baseCommission * 1.5" + }, + { + "_id": "r2-2", + "i2-1": "'gold'", + "o2-1": "1.25", + "o2-2": "baseCommission * 1.25" + }, + { + "_id": "r2-3", + "i2-1": "'silver'", + "o2-1": "1.1", + "o2-2": "baseCommission * 1.1" + }, + { + "_id": "r2-4", + "i2-1": "", + "o2-1": "1.0", + "o2-2": "baseCommission" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Performance Tier", + "field": "performanceTier" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Tier Multiplier", + "field": "tierMultiplier" + }, + { + "id": "o2-2", + "name": "Final Commission", + "field": "finalCommission" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "performanceTierMultipliers", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ex1", + "targetId": "dt2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/insurance-coverage-calculator.json b/test-data/graphs/insurance-coverage-calculator.json new file mode 100644 index 00000000..97683c6a --- /dev/null +++ b/test-data/graphs/insurance-coverage-calculator.json @@ -0,0 +1,362 @@ +{ + "tests": [ + { + "input": { + "customerData": { + "propertyValue": 450000, + "propertyAge": 15, + "propertyType": "single-family", + "preferredDeductible": 1500 + }, + "riskAssessment": { + "areaRiskLevel": "medium", + "claimHistory": { + "pastClaims": 1, + "severityLevel": "low" + } + }, + "additionalRisks": [ + { + "type": "flood", + "level": "medium" + }, + { + "type": "earthquake", + "level": "low" + } + ] + }, + "output": { + "additionalCoverageRecommendations": [ + { + "additionalCoverage": { + "amount": 0, + "recommended": false + }, + "level": "medium", + "type": "flood" + }, + { + "additionalCoverage": { + "amount": 0, + "recommended": false + }, + "level": "low", + "type": "earthquake" + } + ], + "additionalRisks": [ + { + "level": "medium", + "type": "flood" + }, + { + "level": "low", + "type": "earthquake" + } + ], + "basePackage": "basic", + "customerData": { + "preferredDeductible": 1500, + "propertyAge": 15, + "propertyType": "single-family", + "propertyValue": 450000 + }, + "riskAssessment": { + "areaRiskLevel": "medium", + "claimHistory": { + "pastClaims": 1, + "severityLevel": "low" + } + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": ">= 500000", + "i1-2": "'high'", + "o1-1": "'premium'" + }, + { + "_id": "r1-2", + "i1-1": ">= 300000", + "i1-2": "'high'", + "o1-1": "'standard'" + }, + { + "_id": "r1-3", + "i1-1": ">= 500000", + "i1-2": "'medium'", + "o1-1": "'standard'" + }, + { + "_id": "r1-4", + "i1-1": ">= 300000", + "i1-2": "'medium'", + "o1-1": "'basic'" + }, + { + "_id": "r1-5", + "i1-1": ">= 200000", + "i1-2": "'low'", + "o1-1": "'basic'" + }, + { + "_id": "r1-6", + "i1-1": "", + "i1-2": "", + "o1-1": "'minimal'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Property Value", + "field": "customerData.propertyValue" + }, + { + "id": "i1-2", + "name": "Risk Area", + "field": "riskAssessment.areaRiskLevel" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Base Package", + "field": "basePackage" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt1", + "name": "determineBasePackage", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'premium'", + "o2-1": "propertyValue", + "o2-2": "propertyValue * 0.5", + "o2-3": "500000", + "o2-4": "10000", + "o2-5": "1000" + }, + { + "_id": "r2-2", + "i2-1": "'standard'", + "o2-1": "propertyValue * 0.9", + "o2-2": "propertyValue * 0.45", + "o2-3": "300000", + "o2-4": "7500", + "o2-5": "1500" + }, + { + "_id": "r2-3", + "i2-1": "'basic'", + "o2-1": "propertyValue * 0.8", + "o2-2": "propertyValue * 0.4", + "o2-3": "200000", + "o2-4": "5000", + "o2-5": "2000" + }, + { + "_id": "r2-4", + "i2-1": "'minimal'", + "o2-1": "propertyValue * 0.7", + "o2-2": "propertyValue * 0.35", + "o2-3": "100000", + "o2-4": "2500", + "o2-5": "2500" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Base Package", + "field": "basePackage" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Dwelling Coverage", + "field": "coverageLevels.dwellingCoverage" + }, + { + "id": "o2-2", + "name": "Personal Property Coverage", + "field": "coverageLevels.personalPropertyCoverage" + }, + { + "id": "o2-3", + "name": "Liability Coverage", + "field": "coverageLevels.liabilityCoverage" + }, + { + "id": "o2-4", + "name": "Medical Payments Coverage", + "field": "coverageLevels.medicalPaymentsCoverage" + }, + { + "id": "o2-5", + "name": "Deductible", + "field": "coverageLevels.deductible" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "calculateCoverageLevels", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "'flood'", + "i3-2": "'high'", + "o3-1": "true", + "o3-2": "coverageLevels.dwellingCoverage * 0.25" + }, + { + "_id": "r3-2", + "i3-1": "'flood'", + "i3-2": "'medium'", + "o3-1": "true", + "o3-2": "coverageLevels.dwellingCoverage * 0.2" + }, + { + "_id": "r3-3", + "i3-1": "'flood'", + "i3-2": "'low'", + "o3-1": "false", + "o3-2": "0" + }, + { + "_id": "r3-4", + "i3-1": "'earthquake'", + "i3-2": "'high'", + "o3-1": "true", + "o3-2": "coverageLevels.dwellingCoverage * 0.3" + }, + { + "_id": "r3-5", + "i3-1": "'earthquake'", + "i3-2": "'medium'", + "o3-1": "true", + "o3-2": "coverageLevels.dwellingCoverage * 0.2" + }, + { + "_id": "r3-6", + "i3-1": "'earthquake'", + "i3-2": "'low'", + "o3-1": "false", + "o3-2": "0" + }, + { + "_id": "r3-7", + "i3-1": "", + "i3-2": "", + "o3-1": "false", + "o3-2": "0" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Disaster Type", + "field": "additionalRisks.type" + }, + { + "id": "i3-2", + "name": "Risk Level", + "field": "additionalRisks.level" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Recommend", + "field": "additionalCoverage.recommended" + }, + { + "id": "o3-2", + "name": "Coverage Amount", + "field": "additionalCoverage.amount" + } + ], + "passThrough": true, + "inputField": "additionalRisks", + "outputPath": "additionalCoverageRecommendations", + "executionMode": "loop" + }, + "id": "dt3", + "name": "additionalCoverageRecommendations", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt2", + "targetId": "dt3", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/insurance-prior-authorization.json b/test-data/graphs/insurance-prior-authorization.json new file mode 100644 index 00000000..1ed388fd --- /dev/null +++ b/test-data/graphs/insurance-prior-authorization.json @@ -0,0 +1,467 @@ +{ + "tests": [ + { + "input": { + "patientInfo": { + "insuranceType": "Commercial" + }, + "diagnosisCodes": [ + "M54.5", + "M51.26" + ], + "serviceType": "Imaging", + "serviceDetails": { + "code": "70551", + "cost": 1200, + "isEmergency": false + } + }, + "output": { + "reason": "Advanced imaging requires prior authorization", + "requiresAuthorization": true, + "timestamp": 1755622502 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"patientInfo\": {\n \"type\": \"object\",\n \"properties\": {\n \"insuranceType\": {\n \"type\": \"string\",\n \"enum\": [\"Medicaid\", \"Medicare\", \"Commercial\"]\n }\n }\n },\n \"diagnosisCodes\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"serviceType\": {\n \"type\": \"string\",\n \"enum\": [\"Medication\", \"Procedure\", \"Equipment\", \"Imaging\"]\n },\n \"serviceDetails\": {\n \"type\": \"object\",\n \"properties\": {\n \"code\": {\n \"type\": \"string\"\n },\n \"cost\": {\n \"type\": \"number\"\n },\n \"isEmergency\": {\n \"type\": \"boolean\"\n }\n }\n }\n }\n}" + }, + "id": "inputNode", + "name": "request", + "position": { + "x": 110, + "y": 161.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "s1", + "condition": "patientInfo.insuranceType == 'Medicaid'", + "isDefault": false + }, + { + "id": "s2", + "condition": "patientInfo.insuranceType == 'Medicare'", + "isDefault": false + }, + { + "id": "s3", + "condition": "patientInfo.insuranceType == 'Commercial'", + "isDefault": false + }, + { + "id": "s4", + "condition": "", + "isDefault": true + } + ] + }, + "id": "insuranceTypeCheck", + "name": "Insurance Type Check", + "position": { + "x": 430, + "y": 161.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "'Medication'", + "i2": "> 200", + "o1": "true", + "o2": "'High-cost medication requires prior authorization'" + }, + { + "_id": "r2", + "i1": "'Procedure'", + "i2": "> 500", + "o1": "true", + "o2": "'High-cost procedure requires prior authorization'" + }, + { + "_id": "r3", + "i1": "'Imaging'", + "i2": "", + "o1": "true", + "o2": "'All imaging services require prior authorization'" + }, + { + "_id": "r4", + "i1": "'Equipment'", + "i2": "> 300", + "o1": "true", + "o2": "'DME over threshold requires prior authorization'" + }, + { + "_id": "r5", + "i1": "", + "i2": "", + "o1": "false", + "o2": "'Standard service does not require prior authorization'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Service Type", + "field": "serviceType" + }, + { + "id": "i2", + "name": "Cost", + "field": "serviceDetails.cost" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Requires Authorization", + "field": "requiresAuthorization" + }, + { + "id": "o2", + "name": "Reason", + "field": "authorizationReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "medicaidRules", + "name": "Medicaid Rules", + "position": { + "x": 750, + "y": 63.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "'Medication'", + "i2": "contains($, 'J')", + "o1": "true", + "o2": "'Part B medication requires prior authorization'" + }, + { + "_id": "r2", + "i1": "'Procedure'", + "i2": "number($) > 1000", + "o1": "true", + "o2": "'High-cost procedure requires prior authorization'" + }, + { + "_id": "r3", + "i1": "'Imaging'", + "i2": "startsWith($, 'CT') or startsWith($, 'MRI')", + "o1": "true", + "o2": "'Advanced imaging requires prior authorization'" + }, + { + "_id": "r4", + "i1": "'Equipment'", + "i2": "number($) > 500", + "o1": "true", + "o2": "'DME over threshold requires prior authorization'" + }, + { + "_id": "r5", + "i1": "", + "i2": "", + "o1": "false", + "o2": "'Standard Medicare service does not require prior authorization'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Service Type", + "field": "serviceType" + }, + { + "id": "i2", + "name": "Code", + "field": "serviceDetails.code" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Requires Authorization", + "field": "requiresAuthorization" + }, + { + "id": "o2", + "name": "Reason", + "field": "authorizationReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "medicareRules", + "name": "Medicare Rules", + "position": { + "x": 750, + "y": 161.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "'Medication'", + "i2": "contains(serviceDetails.code, 'SPE')", + "o1": "true", + "o2": "'Specialty medication requires prior authorization'" + }, + { + "_id": "r2", + "i1": "'Procedure'", + "i2": "serviceDetails.code in ['33361', '33362', '33363', '33364']", + "o1": "true", + "o2": "'Specific procedures require prior authorization'" + }, + { + "_id": "r3", + "i1": "'Imaging'", + "i2": "serviceDetails.code in ['70450', '70460', '70470', '70551', '70552', '70553']", + "o1": "true", + "o2": "'Advanced imaging requires prior authorization'" + }, + { + "_id": "r4", + "i1": "'Equipment'", + "i2": "serviceDetails.cost > 1000", + "o1": "true", + "o2": "'High-cost equipment requires prior authorization'" + }, + { + "_id": "r5", + "i1": "", + "i2": "serviceDetails.isEmergency == true", + "o1": "false", + "o2": "'Emergency services do not require prior authorization'" + }, + { + "_id": "r6", + "i1": "", + "i2": "", + "o1": "false", + "o2": "'Standard commercial service does not require prior authorization'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Service Type", + "field": "serviceType" + }, + { + "id": "i2", + "name": "Additional Check" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Requires Authorization", + "field": "requiresAuthorization" + }, + { + "id": "o2", + "name": "Reason", + "field": "authorizationReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "commercialRules", + "name": "Commercial Rules", + "position": { + "x": 750, + "y": 259.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1": "some($, startsWith(#, 'Z51'))", + "i2": "requiresAuthorization == true", + "o1": "false", + "o2": "'Encounter for chemotherapy exempt from prior authorization'" + }, + { + "_id": "r2", + "i1": "some($, # in ['O09.511', 'O09.512', 'O09.513', 'O09.519'])", + "i2": "requiresAuthorization == true", + "o1": "false", + "o2": "'Pregnancy-related services exempt from prior authorization'" + }, + { + "_id": "r3", + "i1": "some($, # in ['U07.1'])", + "i2": "requiresAuthorization == true and serviceType == 'Imaging'", + "o1": "false", + "o2": "'COVID-19 related imaging exempt from prior authorization'" + }, + { + "_id": "r4", + "i1": "", + "i2": "", + "o1": "requiresAuthorization", + "o2": "authorizationReason" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Diagnosis Codes", + "field": "diagnosisCodes" + }, + { + "id": "i2", + "name": "Current Authorization Status" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Final Authorization Required", + "field": "requiresAuthorization" + }, + { + "id": "o2", + "name": "Final Reason", + "field": "authorizationReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "diagnosisCheck", + "name": "Diagnosis Code Exclusions", + "position": { + "x": 1070, + "y": 161.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "requiresAuthorization", + "value": "requiresAuthorization" + }, + { + "id": "e2", + "key": "reason", + "value": "authorizationReason" + }, + { + "id": "e3", + "key": "timestamp", + "value": "date('now')" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "finalDetermination", + "name": "Final Determination", + "position": { + "x": 1390, + "y": 161.5 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "inputNode", + "targetId": "insuranceTypeCheck", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "insuranceTypeCheck", + "targetId": "medicaidRules", + "sourceHandle": "s1", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "insuranceTypeCheck", + "targetId": "medicareRules", + "sourceHandle": "s2", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "insuranceTypeCheck", + "targetId": "commercialRules", + "sourceHandle": "s3", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "medicaidRules", + "targetId": "diagnosisCheck", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "medicareRules", + "targetId": "diagnosisCheck", + "type": "edge" + }, + { + "id": "edge7", + "sourceId": "commercialRules", + "targetId": "diagnosisCheck", + "type": "edge" + }, + { + "id": "edge8", + "sourceId": "diagnosisCheck", + "targetId": "finalDetermination", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/insurance-underwriting-risk.json b/test-data/graphs/insurance-underwriting-risk.json new file mode 100644 index 00000000..464dee49 --- /dev/null +++ b/test-data/graphs/insurance-underwriting-risk.json @@ -0,0 +1,321 @@ +{ + "tests": [ + { + "input": { + "applicationId": "APP-12345", + "applicantName": "Jane Smith", + "answers": { + "hasHighRiskMedicalCondition": true, + "recentHospitalization": false, + "multiplePreExistingConditions": true, + "hazardousOccupation": false, + "age": 58, + "coverageAmount": 1200000, + "hasIncompleteInformation": false, + "hasInformationDiscrepancy": true, + "hasForeignResidency": false + } + }, + "output": { + "answers": { + "age": 58, + "coverageAmount": 1200000, + "hasForeignResidency": false, + "hasHighRiskMedicalCondition": true, + "hasIncompleteInformation": false, + "hasInformationDiscrepancy": true, + "hazardousOccupation": false, + "multiplePreExistingConditions": true, + "recentHospitalization": false + }, + "applicantName": "Jane Smith", + "applicationId": "APP-12345", + "riskDescriptions": [ + "High risk medical condition", + "Multiple pre-existing conditions" + ], + "riskFactors": [ + { + "description": "High risk medical condition", + "points": 10 + }, + { + "description": "Multiple pre-existing conditions", + "points": 20 + } + ], + "totalRiskScore": 30, + "underwriting": { + "needsManualReview": false, + "referralReason": "No referral required" + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "application", + "position": { + "x": 110, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "r1-1", + "i1-1": "true", + "i1-2": "", + "i1-3": "", + "i1-4": "", + "i1-5": "", + "o1-1": "10", + "o1-2": "'High risk medical condition'" + }, + { + "_id": "r1-2", + "i1-1": "", + "i1-2": "true", + "i1-3": "", + "i1-4": "", + "i1-5": "", + "o1-1": "15", + "o1-2": "'Recent hospitalization'" + }, + { + "_id": "r1-3", + "i1-1": "", + "i1-2": "", + "i1-3": "true", + "i1-4": "", + "i1-5": "", + "o1-1": "20", + "o1-2": "'Multiple pre-existing conditions'" + }, + { + "_id": "r1-4", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "i1-4": "true", + "i1-5": "", + "o1-1": "25", + "o1-2": "'Hazardous occupation'" + }, + { + "_id": "r1-5", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "i1-4": "", + "i1-5": "> 65", + "o1-1": "15", + "o1-2": "'Advanced age applicant'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Has High Risk Medical Condition", + "field": "answers.hasHighRiskMedicalCondition" + }, + { + "id": "i1-2", + "name": "Recent Hospitalization", + "field": "answers.recentHospitalization" + }, + { + "id": "i1-3", + "name": "Multiple Pre-existing Conditions", + "field": "answers.multiplePreExistingConditions" + }, + { + "id": "i1-4", + "name": "Hazardous Occupation", + "field": "answers.hazardousOccupation" + }, + { + "id": "i1-5", + "name": "Age", + "field": "answers.age" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Risk Points", + "field": "points" + }, + { + "id": "o1-2", + "name": "Risk Description", + "field": "description" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "riskFactors", + "executionMode": "single", + "passThorough": false + }, + "id": "dt1", + "name": "risk_factors", + "position": { + "x": 430, + "y": 292.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "totalRiskScore", + "value": "sum(map(riskFactors ?? [], #.points))" + }, + { + "id": "e1-2", + "key": "riskDescriptions", + "value": "map(riskFactors ?? [], #.description)" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculate_risk_score", + "position": { + "x": 750, + "y": 292.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "> 1500000", + "o2-1": "true", + "o2-2": "'Coverage amount exceeds automatic approval threshold'" + }, + { + "_id": "r2-2", + "i2-2": "> 40", + "o2-1": "true", + "o2-2": "'Risk score exceeds threshold'" + }, + { + "_id": "r2-3", + "i2-3": "true", + "o2-1": "true", + "o2-2": "'Application has incomplete information'" + }, + { + "_id": "r2-4", + "i2-4": "true", + "o2-1": "true", + "o2-2": "'Discrepancy in personal information'" + }, + { + "_id": "r2-5", + "i2-5": "true", + "o2-1": "true", + "o2-2": "'Foreign residency or citizenship'" + }, + { + "_id": "r2-6", + "i2-1": "", + "i2-2": "", + "i2-3": "", + "i2-4": "", + "i2-5": "", + "o2-1": "false", + "o2-2": "'No referral required'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Coverage Amount", + "field": "answers.coverageAmount" + }, + { + "id": "i2-2", + "name": "Risk Score", + "field": "totalRiskScore" + }, + { + "id": "i2-3", + "name": "Incomplete Information", + "field": "answers.hasIncompleteInformation" + }, + { + "id": "i2-4", + "name": "Information Discrepancy", + "field": "answers.hasInformationDiscrepancy" + }, + { + "id": "i2-5", + "name": "Foreign Residency", + "field": "answers.hasForeignResidency" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Needs Manual Review", + "field": "underwriting.needsManualReview" + }, + { + "id": "o2-2", + "name": "Referral Reason", + "field": "underwriting.referralReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt2", + "name": "referral_decision", + "position": { + "x": 1070, + "y": 292.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ex1", + "targetId": "dt2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/international-roaming-policy-manager.json b/test-data/graphs/international-roaming-policy-manager.json new file mode 100644 index 00000000..e61ceccf --- /dev/null +++ b/test-data/graphs/international-roaming-policy-manager.json @@ -0,0 +1,199 @@ +{ + "tests": [ + { + "input": { + "destination": { + "country": "France", + "region": "EU", + "arrivalDate": "2025-03-20", + "departureDate": "2025-03-27" + }, + "customer": { + "id": "C123456789", + "profile": { + "planType": "International Plus", + "isDataRoamingAllowed": true, + "isVoiceRoamingAllowed": true, + "dataRoamingQuota": 5000, + "avgDailyDataUsage": 250, + "avgDailyVoiceUsage": 15, + "avgDailySmsUsage": 10 + }, + "usage": { + "dataRoamingUsed": 1250, + "voiceRoamingUsed": 45, + "smsRoamingUsed": 22 + } + } + }, + "output": { + "isDataRoamingEnabled": true, + "isVoiceRoamingEnabled": true, + "remainingDataAllowance": 3750, + "totalEstimatedDailyCost": 252.75 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "roamingRequest", + "position": { + "x": 110, + "y": 261.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'EU'", + "o1-1": "'premium'", + "o1-2": "'full'", + "o1-3": "1.0", + "o1-4": "0.15", + "o1-5": "0.05" + }, + { + "_id": "r1-2", + "i1-1": "'USA', 'Canada'", + "o1-1": "'standard'", + "o1-2": "'limited'", + "o1-3": "2.0", + "o1-4": "0.25", + "o1-5": "0.10" + }, + { + "_id": "r1-3", + "i1-1": "'Australia', 'New Zealand', 'Japan', 'South Korea'", + "o1-1": "'standard'", + "o1-2": "'limited'", + "o1-3": "2.5", + "o1-4": "0.30", + "o1-5": "0.15" + }, + { + "_id": "r1-4", + "i1-1": "'China', 'India', 'Brazil', 'Russia', 'Mexico'", + "o1-1": "'basic'", + "o1-2": "'restricted'", + "o1-3": "3.5", + "o1-4": "0.40", + "o1-5": "0.25" + }, + { + "_id": "r1-5", + "i1-1": "", + "o1-1": "'minimal'", + "o1-2": "'emergency'", + "o1-3": "5.0", + "o1-4": "0.50", + "o1-5": "0.30" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Region", + "field": "destination.region" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "ServiceTier", + "field": "policy.serviceTier" + }, + { + "id": "o1-2", + "name": "DataAccess", + "field": "policy.dataAccess" + }, + { + "id": "o1-3", + "name": "DataRatePerMB", + "field": "policy.dataRate" + }, + { + "id": "o1-4", + "name": "VoiceRatePerMin", + "field": "policy.voiceRate" + }, + { + "id": "o1-5", + "name": "SMSRatePerMessage", + "field": "policy.smsRate" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "roamingPolicyLookup", + "position": { + "x": 430, + "y": 261.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-2", + "key": "totalEstimatedDailyCost", + "value": "customer.profile.avgDailyDataUsage * policy.dataRate + customer.profile.avgDailyVoiceUsage * policy.voiceRate + customer.profile.avgDailySmsUsage * policy.smsRate" + }, + { + "id": "e1-3", + "key": "isDataRoamingEnabled", + "value": "policy.serviceTier != 'minimal' and customer.profile.isDataRoamingAllowed == true" + }, + { + "id": "e1-4", + "key": "isVoiceRoamingEnabled", + "value": "customer.profile.isVoiceRoamingAllowed == true" + }, + { + "id": "e1-5", + "key": "remainingDataAllowance", + "value": "customer.profile.dataRoamingQuota - customer.usage.dataRoamingUsed" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateRoamingParameters", + "position": { + "x": 750, + "y": 261.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/last-mile-delivery-assignment.json b/test-data/graphs/last-mile-delivery-assignment.json new file mode 100644 index 00000000..a9df5719 --- /dev/null +++ b/test-data/graphs/last-mile-delivery-assignment.json @@ -0,0 +1,373 @@ +{ + "tests": [ + { + "input": { + "package": { + "id": "PKG-12345", + "priority": "express", + "weight": 22.5, + "dimensions": { + "length": 45, + "width": 30, + "height": 25 + }, + "fragile": false, + "needsSignature": true, + "distanceFromDeliveryPerson": 5.2, + "deliveryDeadline": "2025-03-19T16:00:00Z", + "deliveryZone": "downtown", + "specialInstructions": "Leave with doorman if recipient unavailable" + }, + "deliveryPerson": { + "id": "DP-789", + "name": "Alex Johnson", + "skills": [ + "express_certified", + "heavy_lifting", + "collectSignature" + ], + "currentLocation": { + "latitude": 40.7128, + "longitude": -74.006 + }, + "remainingCapacity": 50, + "remainingDeliveries": 8, + "vehicleType": "van", + "collectSignatureEquipped": true, + "currentZone": "downtown", + "shiftEndsAt": "2025-03-19T20:00:00Z" + } + }, + "output": { + "assignmentDetails": { + "assignmentScore": 28, + "deliveryPersonId": "DP-789", + "estimatedArrival": 1755623438, + "packageId": "PKG-12345" + }, + "assignmentStatus": "assigned", + "capacityFactor": 5, + "deliveryPerson": { + "collectSignatureEquipped": true, + "currentLocation": { + "latitude": 40.7128, + "longitude": -74.006 + }, + "currentZone": "downtown", + "id": "DP-789", + "name": "Alex Johnson", + "remainingCapacity": 50, + "remainingDeliveries": 8, + "shiftEndsAt": "2025-03-19T20:00:00Z", + "skills": [ + "express_certified", + "heavy_lifting", + "collectSignature" + ], + "vehicleType": "van" + }, + "distanceScore": 7, + "matchScore": 10, + "message": "Package successfully assigned to delivery person", + "package": { + "deliveryDeadline": "2025-03-19T16:00:00Z", + "deliveryZone": "downtown", + "dimensions": { + "height": 25, + "length": 45, + "width": 30 + }, + "distanceFromDeliveryPerson": 5.2, + "fragile": false, + "id": "PKG-12345", + "needsSignature": true, + "priority": "express", + "specialInstructions": "Leave with doorman if recipient unavailable", + "weight": 22.5 + }, + "priorityLevel": "high", + "recommendedAssignment": true, + "slaFactor": 6, + "totalScore": 28 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 124.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "package.priority == 'express'", + "i1-2": "package.weight > 20", + "i1-3": "contains(deliveryPerson.skills, 'heavy_lifting')", + "o1-1": "10", + "o1-2": "'high'" + }, + { + "_id": "r1-2", + "i1-1": "package.priority == 'express'", + "i1-2": "", + "i1-3": "contains(deliveryPerson.skills, 'express_certified')", + "o1-1": "8", + "o1-2": "'high'" + }, + { + "_id": "r1-3", + "i1-1": "package.priority == 'standard'", + "i1-2": "package.fragile == true", + "i1-3": "contains(deliveryPerson.skills, 'fragile_handling')", + "o1-1": "7", + "o1-2": "'medium'" + }, + { + "_id": "r1-4", + "i1-1": "package.priority == 'standard'", + "i1-2": "package.weight > 15", + "i1-3": "contains(deliveryPerson.skills, 'heavy_lifting')", + "o1-1": "5", + "o1-2": "'medium'" + }, + { + "_id": "r1-5", + "i1-1": "package.needsSignature == true", + "i1-2": "", + "i1-3": "deliveryPerson.collectSignatureEquipped == true", + "o1-1": "4", + "o1-2": "'medium'" + }, + { + "_id": "r1-6", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "o1-1": "2", + "o1-2": "'low'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Package Requirements", + "field": "" + }, + { + "id": "i1-2", + "name": "Package Attributes", + "field": "" + }, + { + "id": "i1-3", + "name": "Delivery Person Qualifications", + "field": "" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Match Score", + "field": "matchScore" + }, + { + "id": "o1-2", + "name": "Priority Level", + "field": "priorityLevel" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "calculate_match_score", + "position": { + "x": 430, + "y": 124.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "distanceScore", + "value": "10 - min([round(package.distanceFromDeliveryPerson / 2), 8])" + }, + { + "id": "e1-2", + "key": "capacityFactor", + "value": "deliveryPerson.remainingCapacity >= package.weight ? 5 : 0" + }, + { + "id": "e1-3", + "key": "slaFactor", + "value": "date(package.deliveryDeadline) - date('now') < 7200 ? 6 : 3" + }, + { + "id": "e1-4", + "key": "totalScore", + "value": "matchScore + $.distanceScore + $.capacityFactor + $.slaFactor" + }, + { + "id": "e1-5", + "key": "recommendedAssignment", + "value": "$.totalScore >= 15" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculate_final_score", + "position": { + "x": 750, + "y": 124.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "s1-1", + "condition": "recommendedAssignment == true", + "isDefault": false + }, + { + "id": "s1-2", + "condition": "", + "isDefault": true + } + ] + }, + "id": "sw1", + "name": "determine_assignment", + "position": { + "x": 1070, + "y": 124.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e2-1", + "key": "assignmentStatus", + "value": "'assigned'" + }, + { + "id": "e2-2", + "key": "assignmentDetails", + "value": "{ 'deliveryPersonId': deliveryPerson.id, 'packageId': package.id, 'estimatedArrival': date('now') + (package.distanceFromDeliveryPerson * 180), 'assignmentScore': totalScore }" + }, + { + "id": "e2-3", + "key": "message", + "value": "'Package successfully assigned to delivery person'" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex2", + "name": "create_assignment", + "position": { + "x": 1390, + "y": 75.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e3-1", + "key": "assignmentStatus", + "value": "'pending'" + }, + { + "id": "e3-2", + "key": "reason", + "value": "totalScore < 15 ? 'Score too low for automatic assignment' : 'Unknown issue'" + }, + { + "id": "e3-3", + "key": "suggestedActions", + "value": "['Try different delivery person', 'Wait for closer delivery person', 'Escalate to dispatch manager']" + }, + { + "id": "e3-4", + "key": "message", + "value": "'Package requires manual review for assignment'" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex3", + "name": "require_manual_review", + "position": { + "x": 1390, + "y": 173.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ex1", + "targetId": "sw1", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "sw1", + "targetId": "ex2", + "sourceHandle": "s1-1", + "type": "edge" + }, + { + "id": "ed5", + "sourceId": "sw1", + "targetId": "ex3", + "sourceHandle": "s1-2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/legacy-plan-management.json b/test-data/graphs/legacy-plan-management.json new file mode 100644 index 00000000..00502c8d --- /dev/null +++ b/test-data/graphs/legacy-plan-management.json @@ -0,0 +1,434 @@ +{ + "tests": [ + { + "input": { + "plan": { + "id": "LEGACY-PLAN-2019", + "name": "Legacy Unlimited Family Plan", + "ageInMonths": 48, + "dataAllowance": 25, + "internationalMinutes": 120, + "features": [ + "Unlimited SMS", + "Free Evening Calls", + "Family Sharing" + ] + }, + "customer": { + "id": "CUST-12345", + "tenureInMonths": 36, + "segment": "Family", + "location": "Urban" + } + }, + "output": { + "migrationEligible": false, + "migrationOfferDetails": "Protected legacy plan - migration not recommended", + "recommendedPlanId": "LEGACY-PLAN-2019", + "simplifiedPlanName": "Legacy Unlimited Family Plan" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "requestNode", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "planName": "contains($, \"Legacy\")", + "planAge": "> 36", + "customerTenure": "> 24", + "o1": "'legacy'", + "o2": "true" + }, + { + "_id": "rule2", + "planName": "contains($, \"Legacy\")", + "planAge": "> 24", + "customerTenure": "", + "o1": "'legacy'", + "o2": "false" + }, + { + "_id": "rule3", + "planName": "contains($, \"Value\") or contains($, \"Essential\")", + "planAge": "", + "customerTenure": "", + "o1": "'value'", + "o2": "false" + }, + { + "_id": "rule4", + "planName": "contains($, \"Premium\") or contains($, \"Unlimited\")", + "planAge": "", + "customerTenure": "", + "o1": "'premium'", + "o2": "false" + }, + { + "_id": "rule5", + "planName": "", + "planAge": "", + "customerTenure": "", + "o1": "'standard'", + "o2": "false" + } + ], + "inputs": [ + { + "id": "planName", + "name": "Plan Name", + "field": "plan.name" + }, + { + "id": "planAge", + "name": "Plan Age (months)", + "field": "plan.ageInMonths" + }, + { + "id": "customerTenure", + "name": "Customer Tenure (months)", + "field": "customer.tenureInMonths" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Plan Category", + "field": "planDetails.category" + }, + { + "id": "o2", + "name": "Grandfathered", + "field": "planDetails.isGrandfathered" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "planIdentifier", + "name": "identifyPlanType", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "benefitRule1", + "planCategory": "'legacy'", + "isGrandfathered": "true", + "o1": "plan.dataAllowance", + "o2": "true", + "o3": "plan.internationalMinutes", + "o4": "'This is a grandfathered legacy plan with protected benefits.'" + }, + { + "_id": "benefitRule2", + "planCategory": "'legacy'", + "isGrandfathered": "false", + "o1": "plan.dataAllowance", + "o2": "false", + "o3": "10", + "o4": "'This is a legacy plan eligible for migration to our current offerings.'" + }, + { + "_id": "benefitRule3", + "planCategory": "'premium'", + "isGrandfathered": "", + "o1": "50", + "o2": "true", + "o3": "100", + "o4": "'Premium plan with our highest tier of benefits.'" + }, + { + "_id": "benefitRule4", + "planCategory": "'value'", + "isGrandfathered": "", + "o1": "15", + "o2": "false", + "o3": "0", + "o4": "'Value plan with essential features.'" + }, + { + "_id": "benefitRule5", + "planCategory": "", + "isGrandfathered": "", + "o1": "25", + "o2": "false", + "o3": "50", + "o4": "'Standard plan with balanced features.'" + } + ], + "inputs": [ + { + "id": "planCategory", + "name": "Plan Category", + "field": "planDetails.category" + }, + { + "id": "isGrandfathered", + "name": "Is Grandfathered", + "field": "planDetails.isGrandfathered" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Data Allowance (GB)", + "field": "planDetails.dataAllowanceGB" + }, + { + "id": "o2", + "name": "Retain Special Features", + "field": "planDetails.retainSpecialFeatures" + }, + { + "id": "o3", + "name": "International Minutes", + "field": "planDetails.internationalMinutes" + }, + { + "id": "o4", + "name": "Plan Description", + "field": "planDetails.description" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "planBenefits", + "name": "determineBenefits", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "mappingRule1", + "category": "'legacy'", + "grandfathered": "true", + "o1": "plan.name", + "o2": "plan.id" + }, + { + "_id": "mappingRule2", + "category": "'legacy'", + "grandfathered": "false", + "o1": "'Telco Essentials Plus'", + "o2": "'PLAN-ESS-001'" + }, + { + "_id": "mappingRule3", + "category": "'premium'", + "grandfathered": "", + "o1": "'Telco Premium Unlimited'", + "o2": "'PLAN-PREM-001'" + }, + { + "_id": "mappingRule4", + "category": "'value'", + "grandfathered": "", + "o1": "'Telco Essentials'", + "o2": "'PLAN-VAL-001'" + }, + { + "_id": "mappingRule5", + "category": "", + "grandfathered": "", + "o1": "'Telco Standard'", + "o2": "'PLAN-STD-001'" + } + ], + "inputs": [ + { + "id": "category", + "name": "Plan Category", + "field": "planDetails.category" + }, + { + "id": "grandfathered", + "name": "Is Grandfathered", + "field": "planDetails.isGrandfathered" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Simplified Plan Name", + "field": "simplifiedPlanName" + }, + { + "id": "o2", + "name": "Recommended Plan ID", + "field": "recommendedPlanId" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "planMapping", + "name": "mapToCurrentCatalog", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "migrationRule1", + "category": "'legacy'", + "grandfathered": "true", + "o1": "false", + "o2": "'Protected legacy plan - migration not recommended'" + }, + { + "_id": "migrationRule2", + "category": "'legacy'", + "grandfathered": "false", + "o1": "true", + "o2": "'Eligible for migration to Telco Essentials Plus with 3 months promotional pricing'" + }, + { + "_id": "migrationRule3", + "category": "", + "grandfathered": "", + "o1": "false", + "o2": "'Current catalog plan - no migration needed'" + } + ], + "inputs": [ + { + "id": "category", + "name": "Plan Category", + "field": "planDetails.category" + }, + { + "id": "grandfathered", + "name": "Is Grandfathered", + "field": "planDetails.isGrandfathered" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Migration Eligible", + "field": "migrationEligible" + }, + { + "id": "o2", + "name": "Migration Offer Details", + "field": "migrationOfferDetails" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "migrationEligibility", + "name": "determineMigrationEligibility", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "80330def-ddbf-4b19-a7f6-bc18ff007bf2", + "key": "plan", + "value": "null" + }, + { + "id": "7940de78-cff0-4041-a5d6-afcfd69b16f3", + "key": "planDetails", + "value": "null" + }, + { + "id": "76c7ccef-80e4-4cd5-8a1a-cd45573ec070", + "key": "customer", + "value": "null" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "e2398550-dac8-4d1f-a720-e09291e34f2e", + "name": "omitFields", + "position": { + "x": 1710, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "requestNode", + "targetId": "planIdentifier", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "planIdentifier", + "targetId": "planBenefits", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "planBenefits", + "targetId": "planMapping", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "planMapping", + "targetId": "migrationEligibility", + "type": "edge" + }, + { + "id": "84bb7505-4ff7-420d-9a9e-673a87e81c98", + "sourceId": "migrationEligibility", + "type": "edge", + "targetId": "e2398550-dac8-4d1f-a720-e09291e34f2e" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/loan-approval.json b/test-data/graphs/loan-approval.json new file mode 100644 index 00000000..25d260f2 --- /dev/null +++ b/test-data/graphs/loan-approval.json @@ -0,0 +1,469 @@ +{ + "tests": [ + { + "input": { + "applicantId": "APL-12345", + "creditScore": 685, + "annualIncome": 72000, + "monthlyDebt": 1800, + "monthlyIncome": 6000, + "employmentYears": 4, + "employmentStatus": "full_time", + "loanAmount": 250000, + "loanTerm": 30 + }, + "output": { + "approval": true, + "baseRate": 5.5, + "interestRate": 6.5, + "riskAdjustment": 20, + "totalRiskScore": 80 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"applicantId\": {\n \"type\": \"string\"\n },\n \"creditScore\": {\n \"type\": \"number\"\n },\n \"annualIncome\": {\n \"type\": \"number\"\n },\n \"monthlyDebt\": {\n \"type\": \"number\"\n },\n \"monthlyIncome\": {\n \"type\": \"number\"\n },\n \"employmentYears\": {\n \"type\": \"number\"\n },\n \"employmentStatus\": {\n \"type\": \"string\"\n },\n \"loanAmount\": {\n \"type\": \"number\"\n },\n \"loanTerm\": {\n \"type\": \"number\"\n }\n }\n}" + }, + "id": "input", + "name": "loanApplication", + "position": { + "x": 110, + "y": 243.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "cs1", + "i1-1": ">= 750", + "o1-1": "\"excellent\"", + "o1-2": "30" + }, + { + "_id": "cs2", + "i1-1": "[700..749]", + "o1-1": "\"good\"", + "o1-2": "25" + }, + { + "_id": "cs3", + "i1-1": "[650..699]", + "o1-1": "\"fair\"", + "o1-2": "15" + }, + { + "_id": "cs4", + "i1-1": "[600..649]", + "o1-1": "\"poor\"", + "o1-2": "5" + }, + { + "_id": "cs5", + "i1-1": "< 600", + "o1-1": "\"very_poor\"", + "o1-2": "0" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Credit Score", + "field": "creditScore" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Credit Rating", + "field": "creditRating" + }, + { + "id": "o1-2", + "name": "Score Points", + "field": "creditScorePoints" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "evaluateCreditScore", + "name": "creditScoreEvaluation", + "position": { + "x": 430, + "y": 243.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "iv1", + "i2-1": ">= 100000", + "o2-1": "\"high\"", + "o2-2": "25" + }, + { + "_id": "iv2", + "i2-1": "[60000..99999]", + "o2-1": "\"medium\"", + "o2-2": "20" + }, + { + "_id": "iv3", + "i2-1": "[30000..59999]", + "o2-1": "\"low\"", + "o2-2": "10" + }, + { + "_id": "iv4", + "i2-1": "< 30000", + "o2-1": "\"very_low\"", + "o2-2": "0" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Annual Income", + "field": "annualIncome" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Income Level", + "field": "incomeLevel" + }, + { + "id": "o2-2", + "name": "Income Points", + "field": "incomePoints" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "evaluateIncome", + "name": "incomeVerification", + "position": { + "x": 750, + "y": 243.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "dti1", + "key": "dtiRatio", + "value": "(monthlyDebt / monthlyIncome) * 100" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "calculateDTI", + "name": "debtToIncomeRatio", + "position": { + "x": 1070, + "y": 243.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "eh1", + "i4-1": "employmentStatus == \"full_time\" and employmentYears >= 5", + "o4-1": "\"very_stable\"", + "o4-2": "20" + }, + { + "_id": "eh2", + "i4-1": "employmentStatus == \"full_time\" and employmentYears >= 2", + "o4-1": "\"stable\"", + "o4-2": "15" + }, + { + "_id": "eh3", + "i4-1": "employmentStatus == \"full_time\" and employmentYears < 2", + "o4-1": "\"new\"", + "o4-2": "10" + }, + { + "_id": "eh4", + "i4-1": "employmentStatus == \"part_time\" and employmentYears >= 2", + "o4-1": "\"moderate\"", + "o4-2": "5" + }, + { + "_id": "eh5", + "i4-1": "employmentStatus == \"part_time\" and employmentYears < 2", + "o4-1": "\"unstable\"", + "o4-2": "0" + }, + { + "_id": "eh6", + "i4-1": "employmentStatus == \"self_employed\" and employmentYears >= 3", + "o4-1": "\"stable\"", + "o4-2": "15" + }, + { + "_id": "eh7", + "i4-1": "employmentStatus == \"self_employed\" and employmentYears < 3", + "o4-1": "\"moderate\"", + "o4-2": "5" + }, + { + "_id": "eh8", + "i4-1": "employmentStatus == \"unemployed\"", + "o4-1": "\"unstable\"", + "o4-2": "0" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "Employment Status" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "Stability", + "field": "employmentStability" + }, + { + "id": "o4-2", + "name": "Employment Points", + "field": "employmentPoints" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "evaluateEmployment", + "name": "employmentHistory", + "position": { + "x": 1390, + "y": 243.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "approval1", + "condition": "len(rejectionReasons) == 0", + "isDefault": false + }, + { + "id": "rejection1", + "condition": "", + "isDefault": true + } + ] + }, + "id": "determineApproval", + "name": "loanApprovalDecision", + "position": { + "x": 2030, + "y": 243.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "ir1", + "key": "totalRiskScore", + "value": "creditScorePoints + incomePoints + employmentPoints + dtiRatio" + }, + { + "id": "ir2", + "key": "approval", + "value": "true" + }, + { + "id": "ir3", + "key": "baseRate", + "value": "5.5" + }, + { + "id": "ir4", + "key": "riskAdjustment", + "value": "100 - $.totalRiskScore" + }, + { + "id": "ir5", + "key": "interestRate", + "value": "$.baseRate + ($.riskAdjustment * 0.05)" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "calculateInterestRate", + "name": "interestRateCalculation", + "position": { + "x": 2350, + "y": 194.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "rr1", + "i5-1": "creditScorePoints < 15", + "o5-1": "\"Poor credit history\"" + }, + { + "_id": "rr2", + "i5-1": "incomePoints < 10", + "o5-1": "\"Insufficient income\"" + }, + { + "_id": "rr3", + "i5-1": "dtiRatio > 40", + "o5-1": "\"High debt-to-income ratio\"" + }, + { + "_id": "rr4", + "i5-1": "employmentPoints < 10", + "o5-1": "\"Unstable employment history\"" + } + ], + "inputs": [ + { + "id": "i5-1", + "name": "Rejection Conditions" + } + ], + "outputs": [ + { + "id": "o5-1", + "name": "Message", + "field": "message" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "rejectionReasons", + "executionMode": "single", + "passThorough": false + }, + "id": "rejectionReason", + "name": "determineLoanRejectionReason", + "position": { + "x": 1710, + "y": 243.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "7f99a05c-4146-4110-a159-e4e3c269f49b", + "key": "rejectionReasons", + "value": "rejectionReasons" + }, + { + "id": "ex2", + "key": "approval", + "value": "false" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "b2ee66ae-cf8f-40a4-8913-209ca02f4aa3", + "name": "rejection", + "position": { + "x": 2350, + "y": 365 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "evaluateCreditScore", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "evaluateCreditScore", + "targetId": "evaluateIncome", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "evaluateIncome", + "targetId": "calculateDTI", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "calculateDTI", + "targetId": "evaluateEmployment", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "determineApproval", + "targetId": "calculateInterestRate", + "sourceHandle": "approval1", + "type": "edge" + }, + { + "id": "cf7b66cb-e68d-4920-81f4-725f71855e2a", + "sourceId": "evaluateEmployment", + "type": "edge", + "targetId": "rejectionReason" + }, + { + "id": "3c8b572d-68c8-42ba-9e0f-59b4a1557199", + "sourceId": "rejectionReason", + "type": "edge", + "targetId": "determineApproval" + }, + { + "id": "04f4e081-8440-4162-8e78-cfa26d68a64a", + "sourceId": "determineApproval", + "type": "edge", + "targetId": "b2ee66ae-cf8f-40a4-8913-209ca02f4aa3", + "sourceHandle": "rejection1" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/marketplace-listing-verification-system.json b/test-data/graphs/marketplace-listing-verification-system.json new file mode 100644 index 00000000..005511c7 --- /dev/null +++ b/test-data/graphs/marketplace-listing-verification-system.json @@ -0,0 +1,334 @@ +{ + "tests": [ + { + "input": { + "listing": { + "id": "LIST12345", + "title": "Designer Handbag - Limited Edition", + "brand": "LuxuryBrand", + "price": 950, + "condition": "New", + "description": "Authentic designer handbag, limited edition, comes with certificate" + }, + "category": { + "id": "CAT789", + "type": "luxury", + "name": "Designer Handbags", + "averagePrice": 1500, + "highValueBrands": [ + "LuxuryBrand", + "PremiumDesigner", + "ExclusiveFashion" + ] + }, + "seller": { + "id": "SELL456", + "name": "FashionReseller", + "rating": 3.8, + "accountAgeDays": 45, + "previousViolations": 1, + "listingsCount": 27 + } + }, + "output": { + "category": { + "averagePrice": 1500, + "highValueBrands": [ + "LuxuryBrand", + "PremiumDesigner", + "ExclusiveFashion" + ], + "id": "CAT789", + "name": "Designer Handbags", + "type": "luxury" + }, + "hasLowRating": true, + "hasPreviousViolations": true, + "isHighValueBrand": true, + "isNewSeller": true, + "isSensitiveCategory": true, + "listing": { + "brand": "LuxuryBrand", + "condition": "New", + "description": "Authentic designer handbag, limited edition, comes with certificate", + "id": "LIST12345", + "price": 950, + "title": "Designer Handbag - Limited Edition" + }, + "priceDeviationScore": 36.666666666666664, + "riskAssessment": { + "level": "high", + "reason": "Suspicious pricing for high-value brand with history of violations" + }, + "seller": { + "accountAgeDays": 45, + "id": "SELL456", + "listingsCount": 27, + "name": "FashionReseller", + "previousViolations": 1, + "rating": 3.8 + }, + "verification": { + "message": "High risk listing requires immediate manual verification", + "required": true, + "type": "manual" + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "priceDeviationScore", + "value": "abs((listing.price - category.averagePrice) / category.averagePrice * 100)" + }, + { + "id": "expr2", + "key": "isSensitiveCategory", + "value": "contains(['luxury', 'electronics', 'collectibles', 'designer'], category.type)" + }, + { + "id": "expr3", + "key": "isHighValueBrand", + "value": "contains(category.highValueBrands ?? [], listing.brand)" + }, + { + "id": "expr4", + "key": "hasLowRating", + "value": "seller.rating < 4.0" + }, + { + "id": "expr5", + "key": "isNewSeller", + "value": "seller.accountAgeDays < 90" + }, + { + "id": "expr6", + "key": "hasPreviousViolations", + "value": "seller.previousViolations > 0" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "calculateRiskFactors", + "name": "calculateRiskFactors", + "position": { + "x": 430, + "y": 115 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "isHighValueBrand == true", + "i2": "priceDeviationScore > 30", + "i3": "hasPreviousViolations == true", + "o1": "'high'", + "o2": "'Suspicious pricing for high-value brand with history of violations'" + }, + { + "_id": "rule2", + "i1": "isHighValueBrand == true", + "i2": "priceDeviationScore > 30", + "i3": "", + "o1": "'high'", + "o2": "'Suspicious pricing for high-value brand'" + }, + { + "_id": "rule3", + "i1": "isHighValueBrand == true", + "i2": "", + "i3": "hasPreviousViolations == true", + "o1": "'medium'", + "o2": "'High-value brand with seller violation history'" + }, + { + "_id": "rule4", + "i1": "", + "i2": "priceDeviationScore > 40", + "i3": "", + "o1": "'medium'", + "o2": "'Significant price deviation from market average'" + }, + { + "_id": "rule5", + "i1": "", + "i2": "", + "i3": "hasPreviousViolations > 2", + "o1": "'medium'", + "o2": "'Multiple previous seller violations'" + }, + { + "_id": "rule6", + "i1": "isNewSeller == true", + "i2": "isSensitiveCategory == true", + "i3": "", + "o1": "'medium'", + "o2": "'New seller listing sensitive category items'" + }, + { + "_id": "rule7", + "i1": "hasLowRating == true", + "i2": "isSensitiveCategory == true", + "i3": "", + "o1": "'medium'", + "o2": "'Low-rated seller with sensitive category items'" + }, + { + "_id": "rule8", + "i1": "", + "i2": "", + "i3": "", + "o1": "'low'", + "o2": "'Standard risk level'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Brand Risk", + "field": "" + }, + { + "id": "i2", + "name": "Price Risk", + "field": "" + }, + { + "id": "i3", + "name": "Seller Risk", + "field": "" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Risk Level", + "field": "riskAssessment.level" + }, + { + "id": "o2", + "name": "Risk Reason", + "field": "riskAssessment.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "evaluateRisk", + "name": "evaluateRiskLevel", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "'high'", + "o1": "true", + "o2": "'manual'", + "o3": "'High risk listing requires immediate manual verification'" + }, + { + "_id": "rule2", + "i1": "'medium'", + "o1": "true", + "o2": "'batch'", + "o3": "'Medium risk listing added to batch verification queue'" + }, + { + "_id": "rule3", + "i1": "'low'", + "o1": "false", + "o2": "'none'", + "o3": "'No verification required'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Risk Level", + "field": "riskAssessment.level" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Requires Verification", + "field": "verification.required" + }, + { + "id": "o2", + "name": "Verification Type", + "field": "verification.type" + }, + { + "id": "o3", + "name": "Verification Message", + "field": "verification.message" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "determineAction", + "name": "determineAction", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "calculateRiskFactors", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "calculateRiskFactors", + "targetId": "evaluateRisk", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "evaluateRisk", + "targetId": "determineAction", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/marketplace-seller-grading-system.json b/test-data/graphs/marketplace-seller-grading-system.json new file mode 100644 index 00000000..982bc92a --- /dev/null +++ b/test-data/graphs/marketplace-seller-grading-system.json @@ -0,0 +1,436 @@ +{ + "tests": [ + { + "input": { + "metrics": { + "onTimeDeliveryRate": 96.5, + "customerSatisfaction": 4.7, + "inventoryAccuracy": 97.2, + "policyCompliance": 94.8 + }, + "sellerInfo": { + "id": "S12345", + "name": "Global Gadgets Store", + "monthsActive": 18 + } + }, + "output": { + "grade": "B", + "recommendedAction": "Eligible for featured seller status", + "status": "Good" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": ">= 98", + "o1-1": "5" + }, + { + "_id": "r1-2", + "i1-1": ">= 95", + "o1-1": "4" + }, + { + "_id": "r1-3", + "i1-1": ">= 90", + "o1-1": "3" + }, + { + "_id": "r1-4", + "i1-1": ">= 85", + "o1-1": "2" + }, + { + "_id": "r1-5", + "i1-1": "", + "o1-1": "1" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "On-Time Delivery Rate", + "field": "metrics.onTimeDeliveryRate" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Score", + "field": "scores.delivery" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt1", + "name": "evaluate_delivery", + "position": { + "x": 430, + "y": -33 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": ">= 4.8", + "o2-1": "5" + }, + { + "_id": "r2-2", + "i2-1": ">= 4.5", + "o2-1": "4" + }, + { + "_id": "r2-3", + "i2-1": ">= 4.0", + "o2-1": "3" + }, + { + "_id": "r2-4", + "i2-1": ">= 3.5", + "o2-1": "2" + }, + { + "_id": "r2-5", + "i2-1": "", + "o2-1": "1" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Customer Satisfaction", + "field": "metrics.customerSatisfaction" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Score", + "field": "scores.customerSatisfaction" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt2", + "name": "evaluate_satisfaction", + "position": { + "x": 430, + "y": 65 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": ">= 99", + "o3-1": "5" + }, + { + "_id": "r3-2", + "i3-1": ">= 95", + "o3-1": "4" + }, + { + "_id": "r3-3", + "i3-1": ">= 90", + "o3-1": "3" + }, + { + "_id": "r3-4", + "i3-1": ">= 85", + "o3-1": "2" + }, + { + "_id": "r3-5", + "i3-1": "", + "o3-1": "1" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Inventory Accuracy", + "field": "metrics.inventoryAccuracy" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Score", + "field": "scores.inventory" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt3", + "name": "evaluate_inventory", + "position": { + "x": 430, + "y": 163 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r4-1", + "i4-1": ">= 98", + "o4-1": "5" + }, + { + "_id": "r4-2", + "i4-1": ">= 95", + "o4-1": "4" + }, + { + "_id": "r4-3", + "i4-1": ">= 90", + "o4-1": "3" + }, + { + "_id": "r4-4", + "i4-1": ">= 85", + "o4-1": "2" + }, + { + "_id": "r4-5", + "i4-1": "", + "o4-1": "1" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "Policy Compliance", + "field": "metrics.policyCompliance" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "Score", + "field": "scores.compliance" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt4", + "name": "evaluate_compliance", + "position": { + "x": 430, + "y": 261 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-5", + "key": "averageScore", + "value": "avg(values(scores))" + }, + { + "id": "e1-6", + "key": "strengths", + "value": "filter(keys(scores), scores[#] >= 4)" + }, + { + "id": "e1-7", + "key": "improvements", + "value": "filter(keys(scores), scores[#] <= 2)" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "scores", + "executionMode": "single" + }, + "id": "ex1", + "name": "aggregate_scores", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r5-1", + "i5-1": ">= 4.5", + "o5-1": "'A'", + "o5-2": "'Outstanding'", + "o5-3": "'Eligible for premium seller status'" + }, + { + "_id": "r5-2", + "i5-1": ">= 3.5", + "o5-1": "'B'", + "o5-2": "'Good'", + "o5-3": "'Eligible for featured seller status'" + }, + { + "_id": "r5-3", + "i5-1": ">= 2.5", + "o5-1": "'C'", + "o5-2": "'Satisfactory'", + "o5-3": "'Standard seller privileges'" + }, + { + "_id": "r5-4", + "i5-1": ">= 1.5", + "o5-1": "'D'", + "o5-2": "'Needs Improvement'", + "o5-3": "'Performance improvement plan required'" + }, + { + "_id": "r5-5", + "i5-1": "", + "o5-1": "'F'", + "o5-2": "'Poor'", + "o5-3": "'Account review required'" + } + ], + "inputs": [ + { + "id": "i5-1", + "name": "Average Score", + "field": "scores.averageScore" + } + ], + "outputs": [ + { + "id": "o5-1", + "name": "Grade", + "field": "grade" + }, + { + "id": "o5-2", + "name": "Status", + "field": "status" + }, + { + "id": "o5-3", + "name": "Action", + "field": "recommendedAction" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt5", + "name": "calculate_final_grade", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ip1", + "targetId": "dt2", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ip1", + "targetId": "dt3", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "ip1", + "targetId": "dt4", + "type": "edge" + }, + { + "id": "ed5", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed6", + "sourceId": "dt2", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed7", + "sourceId": "dt3", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed8", + "sourceId": "dt4", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed9", + "sourceId": "ex1", + "targetId": "dt5", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/medical-appointment-priority-system.json b/test-data/graphs/medical-appointment-priority-system.json new file mode 100644 index 00000000..be60af08 --- /dev/null +++ b/test-data/graphs/medical-appointment-priority-system.json @@ -0,0 +1,446 @@ +{ + "tests": [ + { + "input": { + "patient": { + "age": 72, + "hasChronicCondition": true, + "immunocompromised": false, + "recentHospitalization": true + }, + "appointment": { + "conditionSeverity": "moderate", + "daysWaiting": 12, + "isFollowUp": true + } + }, + "output": { + "priorityFactors": [ + "Moderate condition with follow-up", + "Moderate wait time (8-14 days)", + "Age over 65", + "Chronic condition", + "Recent hospitalization" + ], + "result": { + "priority": "HIGH", + "recommendation": "Schedule within 24-48 hours" + }, + "scores": { + "conditionSeverity": 20, + "riskFactors": 40, + "waitTime": 10 + }, + "totalScore": 70 + } + } + ], + "nodes": [ + { + "id": "inputNode", + "name": "request", + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"patient\": {\n \"type\": \"object\",\n \"properties\": {\n \"age\": {\n \"type\": \"number\"\n },\n \"hasChronicCondition\": {\n \"type\": \"boolean\"\n },\n \"immunocompromised\": {\n \"type\": \"boolean\"\n },\n \"recentHospitalization\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"appointment\": {\n \"type\": \"object\",\n \"properties\": {\n \"conditionSeverity\": {\n \"type\": \"string\",\n \"enum\": [\"mild\", \"moderate\", \"severe\", \"critical\"]\n },\n \"daysWaiting\": {\n \"type\": \"number\"\n },\n \"isFollowUp\": {\n \"type\": \"boolean\"\n }\n }\n }\n }\n}" + }, + "position": { + "x": 110, + "y": 114 + } + }, + { + "id": "riskFactorScoreNode", + "name": "calculateRiskFactorScore", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "_id": "risk1", + "i1-1": "patient.age > 65", + "o1-1": "10", + "o1-2": "'Age over 65'", + "_description": "" + }, + { + "_id": "risk2", + "i1-1": "patient.hasChronicCondition", + "o1-1": "15", + "o1-2": "'Chronic condition'", + "_description": "" + }, + { + "_id": "risk3", + "i1-1": "patient.immunocompromised", + "o1-1": "20", + "o1-2": "'Immunocompromised'", + "_description": "" + }, + { + "_id": "risk4", + "i1-1": "patient.recentHospitalization", + "o1-1": "15", + "o1-2": "'Recent hospitalization'", + "_description": "" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Condition" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Score", + "field": "score" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "message" + } + ], + "hitPolicy": "collect", + "inputField": null, + "outputPath": "riskFactors", + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 430, + "y": 114 + } + }, + { + "id": "conditionSeverityNode", + "name": "evaluateConditionSeverity", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "_id": "severity1", + "i2-1": "'critical'", + "i2-2": "", + "o2-1": "50", + "o2-2": "'Critical condition'" + }, + { + "_id": "severity2", + "i2-1": "'severe'", + "i2-2": "", + "o2-1": "30", + "o2-2": "'Severe condition'" + }, + { + "_id": "severity3", + "i2-1": "'moderate'", + "i2-2": "true", + "o2-1": "20", + "o2-2": "'Moderate condition with follow-up'" + }, + { + "_id": "severity4", + "i2-1": "'moderate'", + "i2-2": "false", + "o2-1": "15", + "o2-2": "'Moderate condition'" + }, + { + "_id": "severity5", + "i2-1": "'mild'", + "i2-2": "true", + "o2-1": "10", + "o2-2": "'Mild condition with follow-up'" + }, + { + "_id": "severity6", + "i2-1": "'mild'", + "i2-2": "false", + "o2-1": "5", + "o2-2": "'Mild condition'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Condition Severity", + "field": "appointment.conditionSeverity" + }, + { + "id": "i2-2", + "name": "Is Follow Up", + "field": "appointment.isFollowUp" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Score", + "field": "scores.conditionSeverity" + }, + { + "id": "o2-2", + "name": "Reason", + "field": "reasons.conditionSeverity" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 1070, + "y": 114 + } + }, + { + "id": "waitTimeScoreNode", + "name": "calculateWaitTimeScore", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "_id": "wait1", + "i3-1": "> 30", + "o3-1": "25", + "o3-2": "'Excessive wait time (> 30 days)'" + }, + { + "_id": "wait2", + "i3-1": "> 14", + "o3-1": "15", + "o3-2": "'Long wait time (15-30 days)'" + }, + { + "_id": "wait3", + "i3-1": "> 7", + "o3-1": "10", + "o3-2": "'Moderate wait time (8-14 days)'" + }, + { + "_id": "wait4", + "i3-1": "> 3", + "o3-1": "5", + "o3-2": "'Short wait time (4-7 days)'" + }, + { + "_id": "wait5", + "i3-1": "", + "o3-1": "0", + "o3-2": "'Minimal wait time (0-3 days)'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Days Waiting", + "field": "appointment.daysWaiting" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Score", + "field": "scores.waitTime" + }, + { + "id": "o3-2", + "name": "Reason", + "field": "reasons.waitTime" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 1390, + "y": 114 + } + }, + { + "id": "totalPriorityScoreNode", + "name": "calculateTotalPriorityScore", + "type": "expressionNode", + "content": { + "inputField": null, + "outputPath": null, + "expressions": [ + { + "id": "expr1", + "key": "totalScore", + "value": "sum(values(scores))" + }, + { + "id": "expr2", + "key": "priorityFactors", + "value": "flatten(values(reasons))" + }, + { + "id": "f7a526e0-582e-4717-b2c1-8b9df0c504d8", + "key": "reasons", + "value": "null" + }, + { + "id": "b4e49a47-a434-484d-807a-739c32a616db", + "key": "patient", + "value": "null" + }, + { + "id": "dba4d54a-67be-4cca-9258-07b52c76fb61", + "key": "appointment", + "value": "null" + } + ], + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 1710, + "y": 114 + } + }, + { + "id": "priorityAssignmentNode", + "name": "assignPriorityLevel", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "_id": "priority1", + "i4-1": ">= 85", + "o4-1": "'URGENT'", + "o4-2": "'Schedule immediately'" + }, + { + "_id": "priority2", + "i4-1": ">= 60", + "o4-1": "'HIGH'", + "o4-2": "'Schedule within 24-48 hours'" + }, + { + "_id": "priority3", + "i4-1": ">= 40", + "o4-1": "'MEDIUM'", + "o4-2": "'Schedule within 1 week'" + }, + { + "_id": "priority4", + "i4-1": ">= 20", + "o4-1": "'STANDARD'", + "o4-2": "'Schedule within 2 weeks'" + }, + { + "_id": "priority5", + "i4-1": "", + "o4-1": "'LOW'", + "o4-2": "'Schedule as available'" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "Total Score", + "field": "totalScore" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "Priority", + "field": "result.priority" + }, + { + "id": "o4-2", + "name": "Recommendation", + "field": "result.recommendation" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 2030, + "y": 114 + } + }, + { + "id": "02b0be40-dfe0-4a11-a9a4-17f66823f0c2", + "name": "riskFactorSummary", + "type": "expressionNode", + "content": { + "inputField": null, + "outputPath": null, + "expressions": [ + { + "id": "dc9c736d-00fb-4a40-b9ec-59012e9cbbad", + "key": "scores.riskFactors", + "value": "sum(map(riskFactors, #.score))" + }, + { + "id": "26479ea2-761e-4c16-975d-b0d26f4e8f8f", + "key": "reasons.riskFactors", + "value": "map(riskFactors, #.message)" + }, + { + "id": "50d71c19-5c0a-4957-8ec0-c45309ad4f45", + "key": "riskFactors", + "value": "null" + } + ], + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 750, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "type": "edge", + "sourceId": "inputNode", + "targetId": "riskFactorScoreNode" + }, + { + "id": "edge3", + "type": "edge", + "sourceId": "conditionSeverityNode", + "targetId": "waitTimeScoreNode" + }, + { + "id": "edge4", + "type": "edge", + "sourceId": "waitTimeScoreNode", + "targetId": "totalPriorityScoreNode" + }, + { + "id": "edge5", + "type": "edge", + "sourceId": "totalPriorityScoreNode", + "targetId": "priorityAssignmentNode" + }, + { + "id": "607f2b6e-b5ca-4cdd-8e59-d1539f9dda2b", + "type": "edge", + "sourceId": "riskFactorScoreNode", + "targetId": "02b0be40-dfe0-4a11-a9a4-17f66823f0c2" + }, + { + "id": "e857ae81-6c47-4630-8706-c9eba58170ff", + "type": "edge", + "sourceId": "02b0be40-dfe0-4a11-a9a4-17f66823f0c2", + "targetId": "conditionSeverityNode" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/medication-dosage-calculator.json b/test-data/graphs/medication-dosage-calculator.json new file mode 100644 index 00000000..ddfae851 --- /dev/null +++ b/test-data/graphs/medication-dosage-calculator.json @@ -0,0 +1,318 @@ +{ + "tests": [ + { + "input": { + "patientId": "P12345", + "medication": "vancomycin", + "weightKg": 65, + "ageYears": 72, + "gfrValue": 45, + "liverFunction": "normal", + "allergies": [ + "penicillin", + "sulfa" + ], + "currentMedications": [ + "metformin", + "lisinopril" + ] + }, + "output": { + "calculatedDose": { + "adjustmentReason": "adjusted for renal function", + "amount": 731.25, + "frequencyHours": "12", + "route": "intravenous", + "unit": "mg" + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"patientId\": { \"type\": \"string\" },\n \"medication\": { \"type\": \"string\" },\n \"weightKg\": { \"type\": \"number\" },\n \"ageYears\": { \"type\": \"number\" },\n \"gfrValue\": { \"type\": \"number\" },\n \"liverFunction\": { \"type\": \"string\", \"enum\": [\"normal\", \"mild\", \"moderate\", \"severe\"] },\n \"allergies\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } },\n \"currentMedications\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } }\n },\n \"required\": [\"patientId\", \"medication\", \"weightKg\", \"ageYears\", \"gfrValue\"]\n}" + }, + "id": "ip1", + "name": "patientData", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "isChild", + "value": "ageYears < 18" + }, + { + "id": "e1-2", + "key": "isElderly", + "value": "ageYears >= 65" + }, + { + "id": "e1-3", + "key": "hasRenalImpairment", + "value": "gfrValue < 60" + }, + { + "id": "e1-4", + "key": "hasLiverImpairment", + "value": "liverFunction != 'normal'" + }, + { + "id": "e1-5", + "key": "weightFactorAdult", + "value": "weightKg / 70" + }, + { + "id": "e1-6", + "key": "weightFactorChild", + "value": "weightKg / 30" + }, + { + "id": "e1-7", + "key": "renalAdjustmentFactor", + "value": "gfrValue < 30 ? 0.5 : (gfrValue < 60 ? 0.75 : 1)" + }, + { + "id": "e1-8", + "key": "liverAdjustmentFactor", + "value": "liverFunction == 'severe' ? 0.5 : (liverFunction == 'moderate' ? 0.75 : (liverFunction == 'mild' ? 0.9 : 1))" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateParameters", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'amoxicillin'", + "i1-2": "true", + "i1-3": "", + "i1-4": "", + "i1-5": "", + "o1-1": "50 * weightKg", + "o1-2": "'mg'", + "o1-3": "'8'", + "o1-4": "'oral'", + "o1-5": "'standard'" + }, + { + "_id": "r1-2", + "i1-1": "'amoxicillin'", + "i1-2": "false", + "i1-3": "", + "i1-4": "", + "i1-5": "", + "o1-1": "500 * weightFactorAdult", + "o1-2": "'mg'", + "o1-3": "'8'", + "o1-4": "'oral'", + "o1-5": "'standard'" + }, + { + "_id": "r1-3", + "i1-1": "'paracetamol'", + "i1-2": "true", + "i1-3": "", + "i1-4": "", + "i1-5": "", + "o1-1": "15 * weightKg", + "o1-2": "'mg'", + "o1-3": "'6'", + "o1-4": "'oral'", + "o1-5": "'standard'" + }, + { + "_id": "r1-4", + "i1-1": "'paracetamol'", + "i1-2": "false", + "i1-3": "", + "i1-4": "", + "i1-5": "true", + "o1-1": "500 * renalAdjustmentFactor", + "o1-2": "'mg'", + "o1-3": "'8'", + "o1-4": "'oral'", + "o1-5": "'adjusted for renal function'" + }, + { + "_id": "r1-5", + "i1-1": "'paracetamol'", + "i1-2": "false", + "i1-3": "", + "i1-4": "", + "i1-5": "", + "o1-1": "1000", + "o1-2": "'mg'", + "o1-3": "'6'", + "o1-4": "'oral'", + "o1-5": "'standard'" + }, + { + "_id": "r1-6", + "i1-1": "'vancomycin'", + "i1-2": "", + "i1-3": "", + "i1-4": "true", + "i1-5": "", + "o1-1": "15 * weightKg * renalAdjustmentFactor", + "o1-2": "'mg'", + "o1-3": "'12'", + "o1-4": "'intravenous'", + "o1-5": "'adjusted for renal function'" + }, + { + "_id": "r1-7", + "i1-1": "'vancomycin'", + "i1-2": "", + "i1-3": "", + "i1-4": "", + "i1-5": "", + "o1-1": "15 * weightKg", + "o1-2": "'mg'", + "o1-3": "'12'", + "o1-4": "'intravenous'", + "o1-5": "'standard'" + }, + { + "_id": "r1-8", + "i1-1": "'warfarin'", + "i1-2": "", + "i1-3": "", + "i1-4": "", + "i1-5": "true", + "o1-1": "2 * liverAdjustmentFactor", + "o1-2": "'mg'", + "o1-3": "'24'", + "o1-4": "'oral'", + "o1-5": "'adjusted for liver function'" + }, + { + "_id": "r1-9", + "i1-1": "'warfarin'", + "i1-2": "", + "i1-3": "true", + "i1-4": "", + "i1-5": "", + "o1-1": "3 * liverAdjustmentFactor", + "o1-2": "'mg'", + "o1-3": "'24'", + "o1-4": "'oral'", + "o1-5": "'adjusted for elderly'" + }, + { + "_id": "r1-10", + "i1-1": "'warfarin'", + "i1-2": "", + "i1-3": "", + "i1-4": "", + "i1-5": "", + "o1-1": "5", + "o1-2": "'mg'", + "o1-3": "'24'", + "o1-4": "'oral'", + "o1-5": "'standard'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Medication", + "field": "medication" + }, + { + "id": "i1-2", + "name": "Is Child", + "field": "isChild" + }, + { + "id": "i1-3", + "name": "Is Elderly", + "field": "isElderly" + }, + { + "id": "i1-4", + "name": "Has Renal Impairment", + "field": "hasRenalImpairment" + }, + { + "id": "i1-5", + "name": "Has Liver Impairment", + "field": "hasLiverImpairment" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Dose Amount", + "field": "calculatedDose.amount" + }, + { + "id": "o1-2", + "name": "Dose Unit", + "field": "calculatedDose.unit" + }, + { + "id": "o1-3", + "name": "Frequency (hours)", + "field": "calculatedDose.frequencyHours" + }, + { + "id": "o1-4", + "name": "Route", + "field": "calculatedDose.route" + }, + { + "id": "o1-5", + "name": "Adjustment Reason", + "field": "calculatedDose.adjustmentReason" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "calculateDosage", + "position": { + "x": 750, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ex1", + "targetId": "dt1", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/municipal-permit-evaluation-system.json b/test-data/graphs/municipal-permit-evaluation-system.json new file mode 100644 index 00000000..33fb256c --- /dev/null +++ b/test-data/graphs/municipal-permit-evaluation-system.json @@ -0,0 +1,364 @@ +{ + "tests": [ + { + "input": { + "applicationType": "building", + "zoneType": "residential", + "buildingHeight": 28, + "squareFootage": 3200, + "safetyScore": 85, + "environmentalImpact": "minimal", + "applicantInfo": { + "name": "John Smith", + "contactEmail": "john.smith@example.com", + "phoneNumber": "555-123-4567" + }, + "propertyAddress": { + "street": "123 Main Street", + "city": "Anytown", + "state": "CA", + "zipCode": "90210" + }, + "projectDescription": "Single-family home construction with attached garage" + }, + "output": { + "applicantInfo": { + "contactEmail": "john.smith@example.com", + "name": "John Smith", + "phoneNumber": "555-123-4567" + }, + "applicationType": "building", + "approvalReason": "Application approved - Minimal environmental impact", + "approvalStatus": "Approved", + "buildingHeight": 28, + "environmentalImpact": "minimal", + "initialApprovalStatus": "Approved", + "isCommercialZone": false, + "isIndoorEvent": false, + "isIndustrialZone": false, + "isOutdoorEvent": false, + "isResidentialZone": true, + "nextSteps": "standard", + "projectDescription": "Single-family home construction with attached garage", + "propertyAddress": { + "city": "Anytown", + "state": "CA", + "street": "123 Main Street", + "zipCode": "90210" + }, + "safetyScore": 85, + "squareFootage": 3200, + "statusReason": "Residential building meets height and safety requirements", + "zoneType": "residential" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "permitRequest", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "isResidentialZone", + "value": "applicationType == 'building' and zoneType == 'residential'" + }, + { + "id": "e1-2", + "key": "isCommercialZone", + "value": "applicationType == 'building' and zoneType == 'commercial'" + }, + { + "id": "e1-3", + "key": "isIndustrialZone", + "value": "applicationType == 'building' and zoneType == 'industrial'" + }, + { + "id": "e1-4", + "key": "isOutdoorEvent", + "value": "applicationType == 'event' and location == 'outdoor'" + }, + { + "id": "e1-5", + "key": "isIndoorEvent", + "value": "applicationType == 'event' and location == 'indoor'" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "applicationClassification", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "isResidentialZone and buildingHeight <= 35", + "i1-2": "< 5000", + "i1-3": ">= 80", + "o1-1": "'Approved'", + "o1-2": "'Residential building meets height and safety requirements'" + }, + { + "_id": "r1-2", + "i1-1": "isResidentialZone and buildingHeight > 35", + "i1-2": "< 5000", + "i1-3": ">= 80", + "o1-1": "'Conditional'", + "o1-2": "'Residential building exceeds height limits, requires variance approval'" + }, + { + "_id": "r1-3", + "i1-1": "isCommercialZone and buildingHeight <= 100", + "i1-2": "< 20000", + "i1-3": ">= 85", + "o1-1": "'Approved'", + "o1-2": "'Commercial building meets standard requirements'" + }, + { + "_id": "r1-4", + "i1-1": "isCommercialZone and buildingHeight > 100", + "i1-2": "", + "i1-3": ">= 85", + "o1-1": "'Conditional'", + "o1-2": "'Commercial building exceeds height limits, requires additional review'" + }, + { + "_id": "r1-5", + "i1-1": "isIndustrialZone", + "i1-2": "", + "i1-3": ">= 90", + "o1-1": "'Conditional'", + "o1-2": "'Industrial buildings require environmental impact assessment'" + }, + { + "_id": "r1-6", + "i1-1": "isOutdoorEvent and expectedAttendees <= 500", + "i1-2": "", + "i1-3": ">= 75", + "o1-1": "'Approved'", + "o1-2": "'Small outdoor event meets safety requirements'" + }, + { + "_id": "r1-7", + "i1-1": "isOutdoorEvent and expectedAttendees > 500", + "i1-2": "", + "i1-3": ">= 85", + "o1-1": "'Conditional'", + "o1-2": "'Large outdoor event requires additional crowd management plan'" + }, + { + "_id": "r1-8", + "i1-1": "isIndoorEvent and safetyScore >= 90", + "i1-2": "", + "i1-3": "", + "o1-1": "'Approved'", + "o1-2": "'Indoor event meets all safety requirements'" + }, + { + "_id": "r1-9", + "i1-1": "", + "i1-2": "", + "i1-3": "< 75", + "o1-1": "'Denied'", + "o1-2": "'Application does not meet minimum safety score requirements'" + }, + { + "_id": "r1-10", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "o1-1": "'Pending'", + "o1-2": "'Application requires manual review'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Application Type", + "field": "" + }, + { + "id": "i1-2", + "name": "Square Footage", + "field": "squareFootage" + }, + { + "id": "i1-3", + "name": "Safety Score", + "field": "safetyScore" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Status", + "field": "initialApprovalStatus" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "statusReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt1", + "name": "initialApprovalCheck", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'Approved'", + "i2-2": "'minimal'", + "o2-1": "'Approved'", + "o2-2": "'Application approved - Minimal environmental impact'", + "o2-3": "'standard'" + }, + { + "_id": "r2-2", + "i2-1": "'Approved'", + "i2-2": "'moderate'", + "o2-1": "'Conditional'", + "o2-2": "'Application requires environmental mitigation plan'", + "o2-3": "'environmental_review'" + }, + { + "_id": "r2-3", + "i2-1": "'Conditional'", + "i2-2": "'minimal'", + "o2-1": "'Conditional'", + "o2-2": "statusReason", + "o2-3": "'standard_review'" + }, + { + "_id": "r2-4", + "i2-1": "'Conditional'", + "i2-2": "'moderate'", + "o2-1": "'Conditional'", + "o2-2": "statusReason + ' and requires environmental assessment'", + "o2-3": "'comprehensive_review'" + }, + { + "_id": "r2-5", + "i2-1": "'Conditional' or 'Approved'", + "i2-2": "'significant'", + "o2-1": "'Denied'", + "o2-2": "'Application denied due to significant environmental impact'", + "o2-3": "'rejected'" + }, + { + "_id": "r2-6", + "i2-1": "'Denied'", + "i2-2": "", + "o2-1": "'Denied'", + "o2-2": "statusReason", + "o2-3": "'rejected'" + }, + { + "_id": "r2-7", + "i2-1": "'Pending'", + "i2-2": "", + "o2-1": "'Pending'", + "o2-2": "statusReason", + "o2-3": "'manual_review'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Initial Status", + "field": "initialApprovalStatus" + }, + { + "id": "i2-2", + "name": "Environmental Impact", + "field": "environmentalImpact" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Final Status", + "field": "approvalStatus" + }, + { + "id": "o2-2", + "name": "Final Reason", + "field": "approvalReason" + }, + { + "id": "o2-3", + "name": "Next Steps", + "field": "nextSteps" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "dt2", + "name": "environmentalCheck", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ex1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt1", + "targetId": "dt2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/mvno-partner-enablement.json b/test-data/graphs/mvno-partner-enablement.json new file mode 100644 index 00000000..8a9c67a4 --- /dev/null +++ b/test-data/graphs/mvno-partner-enablement.json @@ -0,0 +1,313 @@ +{ + "tests": [ + { + "input": { + "partner": { + "id": "mvno-123", + "name": "TechMobile", + "type": "premium", + "ageInMonths": 36, + "subscriberCount": 120000, + "region": "Northeast", + "businessModel": "business-focused" + } + }, + "output": { + "pricing": { + "dataRatePerMB": 0.004, + "revenueShareFactor": 0.85, + "tier": "tier1", + "voiceRatePerMinute": 0.002 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "partnerType": "'premium'", + "partnerAge": "> 24", + "subscribers": "> 100000", + "serviceAccess": "'full'", + "bandwidthPriority": "'high'" + }, + { + "_id": "rule2", + "partnerType": "'premium'", + "partnerAge": "", + "subscribers": "> 50000", + "serviceAccess": "'enhanced'", + "bandwidthPriority": "'medium'" + }, + { + "_id": "rule3", + "partnerType": "'standard'", + "partnerAge": "> 12", + "subscribers": "> 25000", + "serviceAccess": "'standard'", + "bandwidthPriority": "'medium'" + }, + { + "_id": "rule4", + "partnerType": "'standard'", + "partnerAge": "", + "subscribers": "", + "serviceAccess": "'basic'", + "bandwidthPriority": "'low'" + }, + { + "_id": "rule5", + "partnerType": "'startup'", + "partnerAge": "", + "subscribers": "", + "serviceAccess": "'basic'", + "bandwidthPriority": "'low'" + } + ], + "inputs": [ + { + "id": "partnerType", + "name": "Partner Type", + "field": "partner.type" + }, + { + "id": "partnerAge", + "name": "Partner Age (months)", + "field": "partner.ageInMonths" + }, + { + "id": "subscribers", + "name": "Subscriber Count", + "field": "partner.subscriberCount" + } + ], + "outputs": [ + { + "id": "serviceAccess", + "name": "Service Access Level", + "field": "config.serviceAccessLevel" + }, + { + "id": "bandwidthPriority", + "name": "Bandwidth Priority", + "field": "config.bandwidthPriority" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "partnerConfig", + "name": "partnerServiceAccess", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "res1", + "serviceLevel": "'full'", + "dataAlloc": "5000", + "voiceAlloc": "1000000", + "smsAlloc": "2000000", + "apiLevel": "'advanced'" + }, + { + "_id": "res2", + "serviceLevel": "'enhanced'", + "dataAlloc": "2500", + "voiceAlloc": "500000", + "smsAlloc": "1000000", + "apiLevel": "'intermediate'" + }, + { + "_id": "res3", + "serviceLevel": "'standard'", + "dataAlloc": "1000", + "voiceAlloc": "250000", + "smsAlloc": "500000", + "apiLevel": "'intermediate'" + }, + { + "_id": "res4", + "serviceLevel": "'basic'", + "dataAlloc": "500", + "voiceAlloc": "100000", + "smsAlloc": "200000", + "apiLevel": "'basic'" + } + ], + "inputs": [ + { + "id": "serviceLevel", + "name": "Service Access Level", + "field": "config.serviceAccessLevel" + } + ], + "outputs": [ + { + "id": "dataAlloc", + "name": "Data Allocation (GB)", + "field": "resources.dataAllocationGB" + }, + { + "id": "voiceAlloc", + "name": "Voice Minutes", + "field": "resources.voiceMinutes" + }, + { + "id": "smsAlloc", + "name": "SMS Count", + "field": "resources.smsCount" + }, + { + "id": "apiLevel", + "name": "API Access Level", + "field": "resources.apiAccessLevel" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "resourceAllocation", + "name": "networkResourceAllocation", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "pt1", + "i1": "'full'", + "i2": "> 100000", + "o1": "'tier1'", + "o2": "0.85", + "o3": "0.004", + "o4": "0.002" + }, + { + "_id": "pt2", + "i1": "'enhanced'", + "i2": "> 50000", + "o1": "'tier2'", + "o2": "0.88", + "o3": "0.005", + "o4": "0.003" + }, + { + "_id": "pt3", + "i1": "'standard'", + "i2": "> 10000", + "o1": "'tier3'", + "o2": "0.9", + "o3": "0.006", + "o4": "0.003" + }, + { + "_id": "pt4", + "i1": "", + "i2": "", + "o1": "'tier4'", + "o2": "0.95", + "o3": "0.008", + "o4": "0.004" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Service Level", + "field": "config.serviceAccessLevel" + }, + { + "id": "i2", + "name": "Subscriber Count", + "field": "partner.subscriberCount" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Pricing Tier", + "field": "pricing.tier" + }, + { + "id": "o2", + "name": "Revenue Share", + "field": "pricing.revenueShareFactor" + }, + { + "id": "o3", + "name": "Data Cost Per MB", + "field": "pricing.dataRatePerMB" + }, + { + "id": "o4", + "name": "Voice Cost Per Min", + "field": "pricing.voiceRatePerMinute" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "pricingTier", + "name": "partnerPricing", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "partnerConfig", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "partnerConfig", + "targetId": "resourceAllocation", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "resourceAllocation", + "targetId": "pricingTier", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/online-checkin-eligibility.json b/test-data/graphs/online-checkin-eligibility.json new file mode 100644 index 00000000..8592ead0 --- /dev/null +++ b/test-data/graphs/online-checkin-eligibility.json @@ -0,0 +1,285 @@ +{ + "tests": [ + { + "input": { + "passenger": { + "id": "P12345678", + "name": "John Smith", + "hasValidPassport": true, + "hasValidVisa": true, + "requiresSpecialAssistance": false, + "frequentFlyerStatus": "gold" + }, + "flight": { + "flightNumber": "BA123", + "departureTime": "2025-03-20T10:30:00Z", + "origin": "LHR", + "destination": "JFK", + "requiresVisa": true, + "hasSeatSelection": true, + "allowsExtraBaggage": true, + "hasSpecialMealOptions": true + } + }, + "output": { + "canAddBaggage": true, + "canSelectSeat": true, + "isEligible": false, + "message": "You are eligible for online check-in.", + "statusCode": "eligible" + } + } + ], + "nodes": [ + { + "id": "ip1", + "name": "request", + "type": "inputNode", + "content": { + "schema": "" + }, + "position": { + "x": 110, + "y": 164.5 + } + }, + { + "id": "ex1", + "name": "preprocessData", + "type": "expressionNode", + "content": { + "inputField": null, + "outputPath": null, + "expressions": [ + { + "id": "e1-1", + "key": "flightDepartureTime", + "value": "date(flight.departureTime)" + }, + { + "id": "e1-2", + "key": "currentTime", + "value": "date('2025-03-20T08:30:00Z')" + }, + { + "id": "e1-3", + "key": "hoursUntilDeparture", + "value": "($.flightDepartureTime - $.currentTime) / 3600" + }, + { + "id": "e1-4", + "key": "hasRequiredDocuments", + "value": "passenger.hasValidPassport == true and passenger.hasValidVisa == (flight.requiresVisa ?? false)" + } + ], + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 430, + "y": 164.5 + } + }, + { + "id": "dt1", + "name": "checkEligibility", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "_id": "r1-1", + "i1-1": "hoursUntilDeparture < 1.5", + "o1-1": "false", + "o1-2": "'check_in_closed'", + "o1-3": "'Online check-in is closed. Please proceed to the airport for assistance.'" + }, + { + "_id": "r1-2", + "i1-1": "!hasRequiredDocuments", + "o1-1": "false", + "o1-2": "'missing_documents'", + "o1-3": "'Missing required travel documents. Please check-in at the airport.'" + }, + { + "_id": "r1-3", + "i1-1": "passenger.requiresSpecialAssistance", + "o1-1": "false", + "o1-2": "'special_assistance'", + "o1-3": "'Special assistance required. Please check-in at the airport.'" + }, + { + "_id": "r1-4", + "i1-1": "", + "o1-1": "true", + "o1-2": "'eligible'", + "o1-3": "'You are eligible for online check-in.'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Condition" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Is Eligible", + "field": "isEligible" + }, + { + "id": "o1-2", + "name": "Status Code", + "field": "statusCode" + }, + { + "id": "o1-3", + "name": "Message", + "field": "message" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 750, + "y": 164.5 + } + }, + { + "id": "sw1", + "name": "eligibilityCheck", + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "s1-1", + "condition": "isEligible == true", + "isDefault": false + }, + { + "id": "s1-2", + "condition": "", + "isDefault": true + } + ] + }, + "position": { + "x": 1070, + "y": 164.5 + } + }, + { + "id": "ex2", + "name": "additionalServices", + "type": "expressionNode", + "content": { + "inputField": null, + "outputPath": null, + "expressions": [ + { + "id": "01248d19-c35f-4f47-a424-526359696be5", + "key": "isEligible", + "value": "false" + }, + { + "id": "e2-1", + "key": "canSelectSeat", + "value": "flight.hasSeatSelection == true" + }, + { + "id": "e2-2", + "key": "canAddBaggage", + "value": "flight.allowsExtraBaggage == true" + }, + { + "id": "d053c9cd-f974-417a-92fe-ab880d498c5c", + "key": "statusCode", + "value": "statusCode" + }, + { + "id": "44b35986-520b-4615-87ab-fd990e3b501c", + "key": "message", + "value": "message" + } + ], + "passThrough": false, + "executionMode": "single" + }, + "position": { + "x": 1390, + "y": 190 + } + }, + { + "id": "e87f2886-5c3d-42c2-ba78-9c576cc442b7", + "name": "nonEligible", + "type": "expressionNode", + "content": { + "inputField": null, + "outputPath": null, + "expressions": [ + { + "id": "76a5124e-9d0f-4d85-9e21-6e5cb5cc3bdd", + "key": "isEligible", + "value": "false" + }, + { + "id": "377c0312-f2e1-49ea-a9ad-d3abb82e48b5", + "key": "statusCode", + "value": "statusCode" + }, + { + "id": "cbe1da24-a10a-4ac8-ba3c-06740d7be79b", + "key": "message", + "value": "message" + } + ], + "passThrough": false, + "executionMode": "single" + }, + "position": { + "x": 1390, + "y": 330 + } + } + ], + "edges": [ + { + "id": "ed1", + "type": "edge", + "sourceId": "ip1", + "targetId": "ex1" + }, + { + "id": "ed2", + "type": "edge", + "sourceId": "ex1", + "targetId": "dt1" + }, + { + "id": "ed3", + "type": "edge", + "sourceId": "dt1", + "targetId": "sw1" + }, + { + "id": "ed4", + "type": "edge", + "sourceId": "sw1", + "targetId": "ex2", + "sourceHandle": "s1-1" + }, + { + "id": "44445fe0-c343-4f6d-a5dc-bdbec35c4d5f", + "type": "edge", + "sourceId": "sw1", + "targetId": "e87f2886-5c3d-42c2-ba78-9c576cc442b7", + "sourceHandle": "s1-2" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/order-consolidation-system.json b/test-data/graphs/order-consolidation-system.json new file mode 100644 index 00000000..80a0c9bd --- /dev/null +++ b/test-data/graphs/order-consolidation-system.json @@ -0,0 +1,493 @@ +{ + "tests": [ + { + "input": { + "orders": [ + { + "orderId": "ORD-12345", + "customerName": "John Smith", + "deliveryAddress": { + "street": "123 Main St", + "city": "Springfield", + "state": "IL", + "zipCode": "62704", + "coordinates": { + "latitude": 39.7817, + "longitude": -89.6501 + } + }, + "requestedDeliveryDate": "2025-03-25T14:00:00Z", + "orderWeight": 12.5, + "orderItems": 3 + }, + { + "orderId": "ORD-12346", + "customerName": "Jane Doe", + "deliveryAddress": { + "street": "456 Oak Ave", + "city": "Springfield", + "state": "IL", + "zipCode": "62702", + "coordinates": { + "latitude": 39.8021, + "longitude": -89.6443 + } + }, + "requestedDeliveryDate": "2025-03-25T16:00:00Z", + "orderWeight": 8.2, + "orderItems": 2 + } + ], + "distanceKm": 35, + "deliveryWindowDifferenceHours": 24, + "availableCarrierCapacity": 4, + "orderWeight1": 12.5, + "orderWeight2": 8.2, + "carrierDetails": { + "carrierId": "CAR-789", + "maxCapacity": 500, + "currentLoad": 320 + } + }, + "output": { + "availableCarrierCapacity": 4, + "canConsolidate": true, + "carrierDetails": { + "carrierId": "CAR-789", + "currentLoad": 320, + "maxCapacity": 500 + }, + "consolidationAction": "immediate_consolidation", + "consolidationPriority": "high", + "consolidationWeight": 20.7, + "costSavingEstimate": 23.75, + "costSavingsReport": { + "fuelSavings": 5.25, + "laborSavings": 23.75, + "totalSavings": 29 + }, + "deliverySchedule": { + "estimatedDeliveryTime": null, + "notificationRequired": false, + "type": "consolidated" + }, + "deliveryWindowDifferenceHours": 24, + "distanceKm": 35, + "expectedFuelSavings": 5.25, + "explanation": "Orders are nearby, delivery window compatible, and carrier has capacity", + "orderWeight1": 12.5, + "orderWeight2": 8.2, + "orders": [ + { + "customerName": "John Smith", + "deliveryAddress": { + "city": "Springfield", + "coordinates": { + "latitude": 39.7817, + "longitude": -89.6501 + }, + "state": "IL", + "street": "123 Main St", + "zipCode": "62704" + }, + "orderId": "ORD-12345", + "orderItems": 3, + "orderWeight": 12.5, + "requestedDeliveryDate": "2025-03-25T14:00:00Z" + }, + { + "customerName": "Jane Doe", + "deliveryAddress": { + "city": "Springfield", + "coordinates": { + "latitude": 39.8021, + "longitude": -89.6443 + }, + "state": "IL", + "street": "456 Oak Ave", + "zipCode": "62702" + }, + "orderId": "ORD-12346", + "orderItems": 2, + "orderWeight": 8.2, + "requestedDeliveryDate": "2025-03-25T16:00:00Z" + } + ], + "schedulingPriority": "high" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "< 50", + "i1-2": "< 48", + "i1-3": "> 3", + "o1-1": "'high'", + "o1-2": "'Orders are nearby, delivery window compatible, and carrier has capacity'" + }, + { + "_id": "r1-2", + "i1-1": "< 50", + "i1-2": "< 72", + "i1-3": "> 2", + "o1-1": "'medium'", + "o1-2": "'Orders are nearby with slightly different delivery windows but carrier has capacity'" + }, + { + "_id": "r1-3", + "i1-1": "< 100", + "i1-2": "< 48", + "i1-3": "> 2", + "o1-1": "'medium'", + "o1-2": "'Orders are reasonably close with compatible delivery windows and carrier has capacity'" + }, + { + "_id": "r1-4", + "i1-1": "< 100", + "i1-2": "< 72", + "i1-3": "> 1", + "o1-1": "'low'", + "o1-2": "'Orders are reasonably close with slightly different delivery windows and minimal carrier capacity'" + }, + { + "_id": "r1-5", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "o1-1": "'none'", + "o1-2": "'Orders cannot be consolidated due to distance, delivery timing, or carrier capacity'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Distance (km)", + "field": "distanceKm" + }, + { + "id": "i1-2", + "name": "Delivery Window Difference (hours)", + "field": "deliveryWindowDifferenceHours" + }, + { + "id": "i1-3", + "name": "Available Carrier Capacity", + "field": "availableCarrierCapacity" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Consolidation Priority", + "field": "consolidationPriority" + }, + { + "id": "o1-2", + "name": "Explanation", + "field": "explanation" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "evaluateConsolidationFactors", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "canConsolidate", + "value": "consolidationPriority != 'none'" + }, + { + "id": "e1-2", + "key": "consolidationWeight", + "value": "orderWeight1 + orderWeight2" + }, + { + "id": "e1-3", + "key": "expectedFuelSavings", + "value": "distanceKm * 0.15" + }, + { + "id": "e1-4", + "key": "costSavingEstimate", + "value": "distanceKm * 0.25 + 15" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateConsolidationMetrics", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "s1-1", + "condition": "consolidationPriority == 'high'", + "isDefault": false + }, + { + "id": "s1-2", + "condition": "consolidationPriority == 'medium'", + "isDefault": false + }, + { + "id": "s1-3", + "condition": "consolidationPriority == 'low'", + "isDefault": false + }, + { + "id": "s1-4", + "condition": "", + "isDefault": true + } + ] + }, + "id": "sw1", + "name": "routeByConsolidationPriority", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e2-1", + "key": "consolidationAction", + "value": "'immediate_consolidation'" + }, + { + "id": "e2-2", + "key": "schedulingPriority", + "value": "'high'" + }, + { + "id": "e2-3", + "key": "deliverySchedule", + "value": "{'type': 'consolidated', 'estimatedDeliveryTime': requestedDeliveryDate1, 'notificationRequired': false}" + }, + { + "id": "e2-4", + "key": "costSavingsReport", + "value": "{'fuelSavings': expectedFuelSavings, 'laborSavings': costSavingEstimate, 'totalSavings': expectedFuelSavings + costSavingEstimate}" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex2", + "name": "highPriorityProcessing", + "position": { + "x": 1390, + "y": -33 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e3-1", + "key": "consolidationAction", + "value": "'scheduled_consolidation'" + }, + { + "id": "e3-2", + "key": "schedulingPriority", + "value": "'medium'" + }, + { + "id": "e3-3", + "key": "deliverySchedule", + "value": "{'type': 'consolidated', 'estimatedDeliveryTime': requestedDeliveryDate1, 'customerConfirmationRequired': deliveryWindowDifferenceHours > 24}" + }, + { + "id": "e3-4", + "key": "costSavingsReport", + "value": "{'fuelSavings': expectedFuelSavings * 0.9, 'laborSavings': costSavingEstimate * 0.8, 'totalSavings': (expectedFuelSavings * 0.9) + (costSavingEstimate * 0.8)}" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex3", + "name": "mediumPriorityProcessing", + "position": { + "x": 1390, + "y": 65 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e4-1", + "key": "consolidationAction", + "value": "'optional_consolidation'" + }, + { + "id": "e4-2", + "key": "schedulingPriority", + "value": "'low'" + }, + { + "id": "e4-3", + "key": "deliverySchedule", + "value": "{'type': 'potential_consolidation', 'earliestDeliveryTime': requestedDeliveryDate1, 'latestDeliveryTime': requestedDeliveryDate2, 'customerConfirmationRequired': true}" + }, + { + "id": "e4-4", + "key": "additionalReview", + "value": "'required'" + }, + { + "id": "e4-5", + "key": "costSavingsReport", + "value": "{'fuelSavings': expectedFuelSavings * 0.7, 'laborSavings': costSavingEstimate * 0.6, 'totalSavings': (expectedFuelSavings * 0.7) + (costSavingEstimate * 0.6)}" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex4", + "name": "lowPriorityProcessing", + "position": { + "x": 1390, + "y": 163 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e5-1", + "key": "consolidationAction", + "value": "'no_consolidation'" + }, + { + "id": "e5-2", + "key": "schedulingPriority", + "value": "'standard'" + }, + { + "id": "e5-3", + "key": "deliverySchedule", + "value": "{'type': 'separate', 'order1DeliveryTime': requestedDeliveryDate1, 'order2DeliveryTime': requestedDeliveryDate2}" + }, + { + "id": "e5-4", + "key": "costSavingsReport", + "value": "{'fuelSavings': 0, 'laborSavings': 0, 'totalSavings': 0}" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex5", + "name": "standardProcessing", + "position": { + "x": 1390, + "y": 261 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "ex1", + "targetId": "sw1", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "sw1", + "targetId": "ex2", + "sourceHandle": "s1-1", + "type": "edge" + }, + { + "id": "ed5", + "sourceId": "sw1", + "targetId": "ex3", + "sourceHandle": "s1-2", + "type": "edge" + }, + { + "id": "ed6", + "sourceId": "sw1", + "targetId": "ex4", + "sourceHandle": "s1-3", + "type": "edge" + }, + { + "id": "ed7", + "sourceId": "sw1", + "targetId": "ex5", + "sourceHandle": "s1-4", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/partner-revenue-sharing.json b/test-data/graphs/partner-revenue-sharing.json new file mode 100644 index 00000000..0568c271 --- /dev/null +++ b/test-data/graphs/partner-revenue-sharing.json @@ -0,0 +1,244 @@ +{ + "tests": [ + { + "input": { + "partnerType": "content", + "revenueGenerated": 1500000, + "serviceCategory": "streaming", + "customerSegment": "enterprise", + "contractDuration": 24, + "exclusivity": true + }, + "output": { + "baseCommission": 525000, + "bonusCommission": 37950, + "durationMultiplier": 1.1, + "segmentMultiplier": 1.15, + "telcoRevenue": 937050, + "totalCommission": 562950 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"partnerType\": {\n \"type\": \"string\",\n \"description\": \"Type of partner (content, service, technology, etc.)\"\n },\n \"revenueGenerated\": {\n \"type\": \"number\",\n \"description\": \"Total revenue generated by the partner\"\n },\n \"serviceCategory\": {\n \"type\": \"string\",\n \"description\": \"Category of service (streaming, voice, IoT, etc.)\"\n },\n \"customerSegment\": {\n \"type\": \"string\",\n \"description\": \"Segment of customers (consumer, business, enterprise)\"\n },\n \"contractDuration\": {\n \"type\": \"number\",\n \"description\": \"Duration of partnership contract in months\"\n },\n \"exclusivity\": {\n \"type\": \"boolean\",\n \"description\": \"Whether the partnership is exclusive\"\n }\n }\n}\n" + }, + "id": "ip1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1-1": "'content'", + "i1-2": "'streaming'", + "i1-3": "> 1000000", + "i1-4": "true", + "o1-1": "0.35", + "o1-2": "0.02", + "o1-3": "'premium'" + }, + { + "_id": "r2", + "i1-1": "'content'", + "i1-2": "'streaming'", + "i1-3": "> 500000", + "i1-4": "", + "o1-1": "0.30", + "o1-2": "0.015", + "o1-3": "'standard'" + }, + { + "_id": "r3", + "i1-1": "'content'", + "i1-2": "'streaming'", + "i1-3": "", + "i1-4": "", + "o1-1": "0.25", + "o1-2": "0.01", + "o1-3": "'basic'" + }, + { + "_id": "r4", + "i1-1": "'service'", + "i1-2": "'voice'", + "i1-3": "> 750000", + "i1-4": "", + "o1-1": "0.28", + "o1-2": "0.02", + "o1-3": "'premium'" + }, + { + "_id": "r5", + "i1-1": "'service'", + "i1-2": "'voice'", + "i1-3": "", + "i1-4": "", + "o1-1": "0.22", + "o1-2": "0.01", + "o1-3": "'standard'" + }, + { + "_id": "r6", + "i1-1": "'service'", + "i1-2": "'IoT'", + "i1-3": "", + "i1-4": "", + "o1-1": "0.32", + "o1-2": "0.025", + "o1-3": "'technological'" + }, + { + "_id": "r7", + "i1-1": "'technology'", + "i1-2": "", + "i1-3": "> 1000000", + "i1-4": "", + "o1-1": "0.40", + "o1-2": "0.03", + "o1-3": "'strategic'" + }, + { + "_id": "r8", + "i1-1": "'technology'", + "i1-2": "", + "i1-3": "", + "i1-4": "", + "o1-1": "0.35", + "o1-2": "0.02", + "o1-3": "'standard'" + }, + { + "_id": "r9", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "i1-4": "", + "o1-1": "0.20", + "o1-2": "0.01", + "o1-3": "'default'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Partner Type", + "field": "partnerType" + }, + { + "id": "i1-2", + "name": "Service Category", + "field": "serviceCategory" + }, + { + "id": "i1-3", + "name": "Revenue", + "field": "revenueGenerated" + }, + { + "id": "i1-4", + "name": "Exclusivity", + "field": "exclusivity" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Base Commission Rate", + "field": "baseCommissionRate" + }, + { + "id": "o1-2", + "name": "Performance Bonus Rate", + "field": "bonusRate" + }, + { + "id": "o1-3", + "name": "Partner Tier", + "field": "partnerTier" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "partnerCommissionRates", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "durationMultiplier", + "value": "contractDuration <= 12 ? 1 : (contractDuration <= 36 ? 1.1 : 1.2)" + }, + { + "id": "e2", + "key": "segmentMultiplier", + "value": "customerSegment == 'enterprise' ? 1.15 : (customerSegment == 'business' ? 1.1 : 1)" + }, + { + "id": "e3", + "key": "baseCommission", + "value": "revenueGenerated * baseCommissionRate" + }, + { + "id": "e4", + "key": "bonusCommission", + "value": "revenueGenerated * bonusRate * $.durationMultiplier * $.segmentMultiplier" + }, + { + "id": "e5", + "key": "totalCommission", + "value": "$.baseCommission + $.bonusCommission" + }, + { + "id": "e6", + "key": "telcoRevenue", + "value": "revenueGenerated - $.totalCommission" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateCommission", + "position": { + "x": 750, + "y": 114 + } + } + ], + "edges": [ + { + "id": "e1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "e2", + "sourceId": "dt1", + "targetId": "ex1", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/patient-triage-system.json b/test-data/graphs/patient-triage-system.json new file mode 100644 index 00000000..28cc1a05 --- /dev/null +++ b/test-data/graphs/patient-triage-system.json @@ -0,0 +1,406 @@ +{ + "tests": [ + { + "input": { + "vitals": { + "temperature": 38.7, + "heartRate": 115, + "respiratoryRate": 24, + "systolicBP": 165, + "oxygenSaturation": 94 + }, + "symptoms": [ + "moderate pain", + "fever", + "dizziness" + ], + "chiefComplaint": "fracture" + }, + "output": { + "highestFlag": "orange", + "maxWaitTimeMinutes": 10, + "priorityLevel": "Level 2 - Very Urgent" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "vs1", + "i1": "> 39.5", + "i2": ")40..160(", + "i3": ")8..30(", + "i4": ")80..200(", + "i5": "< 90", + "o1": "30", + "o2": "'red'" + }, + { + "_id": "vs2", + "i1": "> 38.5", + "i2": ")50..150(", + "i3": ")10..25(", + "i4": ")90..180(", + "i5": "< 93", + "o1": "20", + "o2": "'orange'" + }, + { + "_id": "vs3", + "i1": "> 38.0", + "i2": ")55..140(", + "i3": ")12..22(", + "i4": ")100..170(", + "i5": "< 95", + "o1": "10", + "o2": "'yellow'" + }, + { + "_id": "vs4", + "i1": "", + "i2": "", + "i3": "", + "i4": "", + "i5": "", + "o1": "0", + "o2": "'green'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Temperature (°C)", + "field": "vitals.temperature" + }, + { + "id": "i2", + "name": "Heart Rate (bpm)", + "field": "vitals.heartRate" + }, + { + "id": "i3", + "name": "Respiratory Rate (bpm)", + "field": "vitals.respiratoryRate" + }, + { + "id": "i4", + "name": "Systolic BP (mmHg)", + "field": "vitals.systolicBP" + }, + { + "id": "i5", + "name": "O2 Saturation (%)", + "field": "vitals.oxygenSaturation" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Score", + "field": "scores.vitalScore" + }, + { + "id": "o2", + "name": "Flag", + "field": "flags.vitalFlag" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "vitalSigns", + "name": "vital_signs_assessment", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "sym1", + "i1": "some(symptoms, # in [\"severe pain\", \"chest pain\", \"difficulty breathing\", \"unconscious\", \"unresponsive\", \"active bleeding\"])", + "o1": "30", + "o2": "'red'" + }, + { + "_id": "sym2", + "i1": "some(symptoms, # in [\"moderate pain\", \"vomiting\", \"dehydration\", \"fever\", \"dizziness\", \"head injury\"])", + "o1": "20", + "o2": "'orange'" + }, + { + "_id": "sym3", + "i1": "some(symptoms, # in [\"mild pain\", \"nausea\", \"minor injury\", \"rash\", \"cough\"])", + "o1": "10", + "o2": "'yellow'" + }, + { + "_id": "sym4", + "i1": "", + "o1": "0", + "o2": "'green'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Expression" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Score", + "field": "scores.symptomScore" + }, + { + "id": "o2", + "name": "Flag", + "field": "flags.symptomFlag" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "symptoms", + "name": "symptom_assessment", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "cc1", + "i1": "\"stroke\", \"heart attack\", \"cardiac arrest\", \"trauma\", \"anaphylaxis\", \"overdose\", \"seizure\"", + "o1": "40", + "o2": "'red'" + }, + { + "_id": "cc2", + "i1": "\"fracture\", \"deep cut\", \"burn\", \"allergic reaction\", \"infection\", \"pregnancy complication\"", + "o1": "20", + "o2": "'orange'" + }, + { + "_id": "cc3", + "i1": "\"sprain\", \"minor cut\", \"cold\", \"flu\", \"ear pain\", \"medication refill\"", + "o1": "10", + "o2": "'yellow'" + }, + { + "_id": "cc4", + "i1": "", + "o1": "0", + "o2": "'green'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Chief Complaint", + "field": "chiefComplaint" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Score", + "field": "scores.complaintScore" + }, + { + "id": "o2", + "name": "Flag", + "field": "flags.complaintFlag" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "chiefComplaint", + "name": "chief_complaint_assessment", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "cp1", + "i1": "contains($, 'red')", + "i2": ">= 60", + "o1": "'Level 1 - Immediate'", + "o2": "0", + "o3": "'red'" + }, + { + "_id": "cp2", + "i1": "contains($, 'red')", + "i2": ">= 40", + "o1": "'Level 2 - Very Urgent'", + "o2": "10", + "o3": "'red'" + }, + { + "_id": "cp3", + "i1": "contains($, 'orange')", + "i2": ">= 40", + "o1": "'Level 2 - Very Urgent'", + "o2": "10", + "o3": "'orange'" + }, + { + "_id": "cp4", + "i1": "", + "i2": ">= 40", + "o1": "'Level 2 - Very Urgent'", + "o2": "10", + "o3": "'orange'" + }, + { + "_id": "cp5", + "i1": "contains($, 'orange')", + "i2": ">= 20", + "o1": "'Level 3 - Urgent'", + "o2": "30", + "o3": "'orange'" + }, + { + "_id": "cp6", + "i1": "", + "i2": ">= 20", + "o1": "'Level 3 - Urgent'", + "o2": "30", + "o3": "'yellow'" + }, + { + "_id": "cp7", + "i1": "contains($, 'yellow')", + "i2": ">= 10", + "o1": "'Level 4 - Standard'", + "o2": "60", + "o3": "'yellow'" + }, + { + "_id": "cp8", + "i1": "", + "i2": ">= 10", + "o1": "'Level 4 - Standard'", + "o2": "60", + "o3": "'green'" + }, + { + "_id": "cp9", + "i1": "", + "i2": "", + "o1": "'Level 5 - Non-Urgent'", + "o2": "120", + "o3": "'green'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "All flags", + "field": "values(flags)" + }, + { + "id": "i2", + "name": "Total Score", + "field": "scores.vitalScore + scores.symptomScore + scores.complaintScore" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Priority Level", + "field": "priorityLevel" + }, + { + "id": "o2", + "name": "Max Wait Time (minutes)", + "field": "maxWaitTimeMinutes" + }, + { + "id": "o3", + "name": "Highest Flag", + "field": "highestFlag" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "calculatePriority", + "name": "calculate_priority_level", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "vitalSigns", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "vitalSigns", + "targetId": "symptoms", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "symptoms", + "targetId": "chiefComplaint", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "chiefComplaint", + "targetId": "calculatePriority", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/payment-routing-and-fee-calculator.json b/test-data/graphs/payment-routing-and-fee-calculator.json new file mode 100644 index 00000000..3f4308fe --- /dev/null +++ b/test-data/graphs/payment-routing-and-fee-calculator.json @@ -0,0 +1,475 @@ +{ + "tests": [ + { + "input": { + "payment": { + "id": "pmt_12345678", + "type": "credit_card", + "amount": 2500, + "currency": "USD", + "channel": "web", + "timestamp": "2025-03-18T10:30:45Z", + "customer_id": "cust_87654321", + "metadata": { + "card_last_four": "4242", + "card_network": "Visa", + "save_for_future": true + } + }, + "merchant": { + "id": "merch_98765432", + "category": "retail", + "country": "US", + "processing_history": { + "total_transactions": 1256, + "average_amount": 175.5, + "chargeback_rate": 0.2 + } + }, + "session": { + "ip_address": "192.168.1.1", + "device_id": "dev_abcdef123456", + "browser": "Chrome", + "location": { + "country": "US", + "state": "CA", + "city": "San Francisco" + } + } + }, + "output": { + "routing": { + "processing_instructions": { + "fraud_scan": "standard", + "manual_review": true, + "priority": "medium", + "processor": "credit_processor", + "velocity_check": true, + "verification_required": "3ds" + } + }, + "security": { + "fraud_scan_level": "standard", + "high_risk_flag": true, + "total_risk_score": 50, + "velocity_check_required": true + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "payment-input", + "name": "payment-request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule-credit-card", + "input-payment-type": "'credit_card'", + "output-route": "'credit_processor'", + "output-base-fee": "2.9", + "output-risk-score": "25" + }, + { + "_id": "rule-debit-card", + "input-payment-type": "'debit_card'", + "output-route": "'debit_processor'", + "output-base-fee": "1.5", + "output-risk-score": "15" + }, + { + "_id": "rule-bank-transfer", + "input-payment-type": "'bank_transfer'", + "output-route": "'ach_processor'", + "output-base-fee": "1.0", + "output-risk-score": "10" + }, + { + "_id": "rule-crypto", + "input-payment-type": "'cryptocurrency'", + "output-route": "'crypto_processor'", + "output-base-fee": "1.8", + "output-risk-score": "35" + }, + { + "_id": "rule-digital-wallet", + "input-payment-type": "'digital_wallet'", + "output-route": "'wallet_processor'", + "output-base-fee": "2.5", + "output-risk-score": "20" + }, + { + "_id": "rule-default", + "input-payment-type": "", + "output-route": "'default_processor'", + "output-base-fee": "3.5", + "output-risk-score": "50" + } + ], + "inputs": [ + { + "id": "input-payment-type", + "name": "Payment Type", + "field": "payment.type" + } + ], + "outputs": [ + { + "id": "output-route", + "name": "Processor Route", + "field": "routing.processor" + }, + { + "id": "output-base-fee", + "name": "Base Fee Percentage", + "field": "fee.base_percentage" + }, + { + "id": "output-risk-score", + "name": "Risk Score", + "field": "security.base_risk_score" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "payment-type-table", + "name": "payment-type-processing", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule-web-high-risk", + "input-channel": "'web'", + "input-risk-score": "> 30", + "output-channel-fee": "0.5", + "output-channel-risk": "15", + "output-priority": "'low'" + }, + { + "_id": "rule-web-low-risk", + "input-channel": "'web'", + "input-risk-score": "<= 30", + "output-channel-fee": "0.3", + "output-channel-risk": "5", + "output-priority": "'medium'" + }, + { + "_id": "rule-mobile-high-risk", + "input-channel": "'mobile'", + "input-risk-score": "> 30", + "output-channel-fee": "0.8", + "output-channel-risk": "20", + "output-priority": "'low'" + }, + { + "_id": "rule-mobile-low-risk", + "input-channel": "'mobile'", + "input-risk-score": "<= 30", + "output-channel-fee": "0.5", + "output-channel-risk": "10", + "output-priority": "'medium'" + }, + { + "_id": "rule-pos-high-risk", + "input-channel": "'pos'", + "input-risk-score": "> 30", + "output-channel-fee": "1.0", + "output-channel-risk": "5", + "output-priority": "'medium'" + }, + { + "_id": "rule-pos-low-risk", + "input-channel": "'pos'", + "input-risk-score": "<= 30", + "output-channel-fee": "0.8", + "output-channel-risk": "0", + "output-priority": "'high'" + }, + { + "_id": "rule-api-integration", + "input-channel": "'api'", + "input-risk-score": "", + "output-channel-fee": "0.1", + "output-channel-risk": "5", + "output-priority": "'high'" + }, + { + "_id": "rule-default-channel", + "input-channel": "", + "input-risk-score": "", + "output-channel-fee": "1.0", + "output-channel-risk": "25", + "output-priority": "'low'" + } + ], + "inputs": [ + { + "id": "input-channel", + "name": "Channel", + "field": "payment.channel" + }, + { + "id": "input-risk-score", + "name": "Base Risk Score", + "field": "security.base_risk_score" + } + ], + "outputs": [ + { + "id": "output-channel-fee", + "name": "Channel Fee Addition", + "field": "fee.channel_addition" + }, + { + "id": "output-channel-risk", + "name": "Channel Risk Addition", + "field": "security.channel_risk_addition" + }, + { + "id": "output-priority", + "name": "Processing Priority", + "field": "routing.priority" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "channel-routing-table", + "name": "channel-routing", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule-high-amount", + "input-amount": ">= 10000", + "input-route": "", + "output-amount-fee": "-0.5", + "output-amount-security": "30", + "output-verification": "'3ds_and_manual'" + }, + { + "_id": "rule-medium-high-amount", + "input-amount": ">= 5000, < 10000", + "input-route": "", + "output-amount-fee": "-0.3", + "output-amount-security": "20", + "output-verification": "'3ds'" + }, + { + "_id": "rule-medium-amount", + "input-amount": ">= 1000, < 5000", + "input-route": "", + "output-amount-fee": "0", + "output-amount-security": "10", + "output-verification": "'cvv_check'" + }, + { + "_id": "rule-low-amount", + "input-amount": "< 1000", + "input-route": "", + "output-amount-fee": "0.5", + "output-amount-security": "0", + "output-verification": "'standard'" + }, + { + "_id": "rule-high-amount-bank", + "input-amount": ">= 5000", + "input-route": "'ach_processor'", + "output-amount-fee": "-0.8", + "output-amount-security": "15", + "output-verification": "'account_verification'" + }, + { + "_id": "rule-high-amount-crypto", + "input-amount": ">= 5000", + "input-route": "'crypto_processor'", + "output-amount-fee": "0", + "output-amount-security": "40", + "output-verification": "'blockchain_verification'" + } + ], + "inputs": [ + { + "id": "input-amount", + "name": "Payment Amount", + "field": "payment.amount" + }, + { + "id": "input-route", + "name": "Processor Route", + "field": "routing.processor" + } + ], + "outputs": [ + { + "id": "output-amount-fee", + "name": "Amount-based Fee Adjustment", + "field": "fee.amount_adjustment" + }, + { + "id": "output-amount-security", + "name": "Amount-based Security Addition", + "field": "security.amount_risk_addition" + }, + { + "id": "output-verification", + "name": "Verification Method", + "field": "security.verification_method" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "amount-processing", + "name": "amount-based-processing", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr-total-fee-percentage", + "key": "final_fee_percentage", + "value": "fee.base_percentage + fee.channel_addition + fee.amount_adjustment" + }, + { + "id": "expr-fee-amount", + "key": "fee_amount", + "value": "payment.amount * ($.final_fee_percentage / 100)" + }, + { + "id": "expr-minimum-fee", + "key": "fee.final_amount", + "value": "$.fee_amount < 0.5 ? 0.5 : $.fee_amount" + }, + { + "id": "expr-net-amount", + "key": "payment.net_amount", + "value": "payment.amount - $.fee.final_amount" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "fee-calculation", + "name": "fee-calculation", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr-total-risk-score", + "key": "security.total_risk_score", + "value": "security.base_risk_score + security.channel_risk_addition + security.amount_risk_addition" + }, + { + "id": "expr-high-risk-flag", + "key": "security.high_risk_flag", + "value": "$.security.total_risk_score >= 50" + }, + { + "id": "expr-velocity-check", + "key": "security.velocity_check_required", + "value": "$.security.total_risk_score >= 30" + }, + { + "id": "expr-fraud-scan", + "key": "security.fraud_scan_level", + "value": "$.security.total_risk_score >= 75 ? \"enhanced\" : $.security.total_risk_score >= 50 ? \"standard\" : $.security.total_risk_score >= 25 ? \"basic\" : \"minimal\"" + }, + { + "id": "expr-processing-instructions", + "key": "routing.processing_instructions", + "value": "{\n \"priority\": routing.priority,\n \"processor\": routing.processor,\n \"verification_required\": security.verification_method,\n \"fraud_scan\": $.security.fraud_scan_level,\n \"velocity_check\": $.security.velocity_check_required,\n \"manual_review\": $.security.high_risk_flag\n}" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "security-requirements", + "name": "security-verification", + "position": { + "x": 1710, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge-input-to-payment-type", + "sourceId": "payment-input", + "targetId": "payment-type-table", + "type": "edge" + }, + { + "id": "edge-payment-type-to-channel", + "sourceId": "payment-type-table", + "targetId": "channel-routing-table", + "type": "edge" + }, + { + "id": "edge-channel-to-amount", + "sourceId": "channel-routing-table", + "targetId": "amount-processing", + "type": "edge" + }, + { + "id": "edge-amount-to-fees", + "sourceId": "amount-processing", + "targetId": "fee-calculation", + "type": "edge" + }, + { + "id": "edge-fees-to-security", + "sourceId": "fee-calculation", + "targetId": "security-requirements", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/policy-discount-calculator.json b/test-data/graphs/policy-discount-calculator.json new file mode 100644 index 00000000..6832bd24 --- /dev/null +++ b/test-data/graphs/policy-discount-calculator.json @@ -0,0 +1,307 @@ +{ + "tests": [ + { + "input": { + "customer": { + "id": "C12345", + "name": "Jane Smith", + "yearsAsCustomer": 4, + "numberOfPolicies": 2 + }, + "policy": { + "id": "P98765", + "type": "auto", + "basePremium": 1200, + "safetyFeatures": [ + "antiTheftSystem", + "advancedDriverAssistance" + ] + } + }, + "output": { + "customer": { + "id": "C12345", + "name": "Jane Smith", + "numberOfPolicies": 2, + "yearsAsCustomer": 4 + }, + "discounts": { + "bundle": { + "description": "Dual policy discount", + "percentage": 7 + }, + "loyalty": { + "description": "Standard loyalty discount", + "percentage": 10 + }, + "safetyFeatures": [ + { + "description": "Anti-theft system discount", + "percentage": 3 + }, + { + "description": "ADAS discount", + "percentage": 5 + } + ] + }, + "finalPremium": 900, + "maximumDiscountPercentage": 25, + "policy": { + "basePremium": 1200, + "id": "P98765", + "safetyFeatures": [ + "antiTheftSystem", + "advancedDriverAssistance" + ], + "type": "auto" + }, + "totalDiscountPercentage": 25 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "inputNode", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": ">= 5", + "o1-1": "15", + "o1-2": "'Premium loyalty discount'" + }, + { + "_id": "r1-2", + "i1-1": ">= 3", + "o1-1": "10", + "o1-2": "'Standard loyalty discount'" + }, + { + "_id": "r1-3", + "i1-1": ">= 1", + "o1-1": "5", + "o1-2": "'Basic loyalty discount'" + }, + { + "_id": "r1-4", + "i1-1": "", + "o1-1": "0", + "o1-2": "'No loyalty discount'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Years as Customer", + "field": "customer.yearsAsCustomer" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Loyalty Discount Percentage", + "field": "discounts.loyalty.percentage" + }, + { + "id": "o1-2", + "name": "Loyalty Discount Description", + "field": "discounts.loyalty.description" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "loyaltyDiscountsTable", + "name": "customerLoyaltyDiscounts", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": ">= 3", + "o2-1": "12", + "o2-2": "'Multi-policy premium discount'" + }, + { + "_id": "r2-2", + "i2-1": "2", + "o2-1": "7", + "o2-2": "'Dual policy discount'" + }, + { + "_id": "r2-3", + "i2-1": "", + "o2-1": "0", + "o2-2": "'No bundle discount'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Number of Policies", + "field": "customer.numberOfPolicies" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Bundle Discount Percentage", + "field": "discounts.bundle.percentage" + }, + { + "id": "o2-2", + "name": "Bundle Discount Description", + "field": "discounts.bundle.description" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "bundledPoliciesTable", + "name": "bundledPoliciesDiscounts", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "r3-1", + "i3-1": "contains($, 'antiTheftSystem')", + "o3-1": "3", + "o3-2": "'Anti-theft system discount'" + }, + { + "_id": "r3-2", + "i3-1": "contains($, 'dashCam')", + "o3-1": "2", + "o3-2": "'Dash cam discount'" + }, + { + "_id": "r3-3", + "i3-1": "contains($, 'advancedDriverAssistance')", + "o3-1": "5", + "o3-2": "'ADAS discount'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Safety Features", + "field": "policy.safetyFeatures" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Feature Discount", + "field": "percentage" + }, + { + "id": "o3-2", + "name": "Feature Description", + "field": "description" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "discounts.safetyFeatures", + "executionMode": "single", + "passThorough": false + }, + "id": "safetyFeaturesTable", + "name": "safetyFeaturesDiscounts", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "totalDiscountPercentage", + "value": "discounts.loyalty.percentage + discounts.bundle.percentage + sum(map(discounts.safetyFeatures, #.percentage))" + }, + { + "id": "e2", + "key": "maximumDiscountPercentage", + "value": "min([$.totalDiscountPercentage, 25])" + }, + { + "id": "e3", + "key": "finalPremium", + "value": "policy.basePremium * (1 - ($.maximumDiscountPercentage / 100))" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "totalDiscountCalculation", + "name": "calculateTotalDiscount", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "e1", + "sourceId": "inputNode", + "targetId": "loyaltyDiscountsTable", + "type": "edge" + }, + { + "id": "e2", + "sourceId": "loyaltyDiscountsTable", + "targetId": "bundledPoliciesTable", + "type": "edge" + }, + { + "id": "e3", + "sourceId": "bundledPoliciesTable", + "targetId": "safetyFeaturesTable", + "type": "edge" + }, + { + "id": "e4", + "sourceId": "safetyFeaturesTable", + "targetId": "totalDiscountCalculation", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/policy-eligibility-analyzer.json b/test-data/graphs/policy-eligibility-analyzer.json new file mode 100644 index 00000000..b36211de --- /dev/null +++ b/test-data/graphs/policy-eligibility-analyzer.json @@ -0,0 +1,299 @@ +{ + "tests": [ + { + "input": { + "customer": { + "age": 45, + "location": { + "country": "US", + "state": "CA", + "city": "San Francisco" + }, + "healthScore": 85, + "riskFactors": { + "count": 2, + "factors": [ + "previous_claim", + "family_history" + ] + } + } + }, + "output": { + "customer": { + "age": 45, + "healthScore": 85, + "location": { + "city": "San Francisco", + "country": "US", + "state": "CA" + }, + "riskFactors": { + "count": 2, + "factors": [ + "previous_claim", + "family_history" + ] + } + }, + "denialReasons": [], + "eligibility": { + "age": { + "isEligible": true, + "reason": "Age requirements met" + }, + "location": { + "isEligible": true, + "reason": "Location requirements met" + }, + "riskFactors": { + "isEligible": true, + "reason": "Risk factor assessment passed" + } + }, + "isEligible": true, + "policyDecision": { + "approved": null, + "reasons": null + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1-1": "< 18", + "o1-1": "false", + "o1-2": "'Age below minimum requirement'" + }, + { + "_id": "rule2", + "i1-1": "> 75", + "o1-1": "false", + "o1-2": "'Age exceeds maximum limit'" + }, + { + "_id": "rule3", + "i1-1": "", + "o1-1": "true", + "o1-2": "'Age requirements met'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Age", + "field": "customer.age" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Eligible", + "field": "eligibility.age.isEligible" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "eligibility.age.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ageEligibility", + "name": "Age Eligibility", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1-1": "contains(['FL', 'LA', 'TX'], $)", + "o1-1": "false", + "o1-2": "'High risk location'" + }, + { + "_id": "rule2", + "i1-1": "!contains(['US', 'CA', 'UK'], $)", + "o1-1": "false", + "o1-2": "'Location not supported'" + }, + { + "_id": "rule3", + "i1-1": "", + "o1-1": "true", + "o1-2": "'Location requirements met'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "State/Region", + "field": "customer.location.state" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Eligible", + "field": "eligibility.location.isEligible" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "eligibility.location.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "locationEligibility", + "name": "Location Eligibility", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1-1": "> 3", + "o1-1": "false", + "o1-2": "'Too many high-risk factors'" + }, + { + "_id": "rule2", + "i1-1": "== 3 and customer.healthScore < 70", + "o1-1": "false", + "o1-2": "'Combination of risk factors and low health score'" + }, + { + "_id": "rule3", + "i1-1": "", + "o1-1": "true", + "o1-2": "'Risk factor assessment passed'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Risk Factors Count", + "field": "customer.riskFactors.count" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Eligible", + "field": "eligibility.riskFactors.isEligible" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "eligibility.riskFactors.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "riskFactors", + "name": "Risk Factor Assessment", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "isEligible", + "value": "eligibility.age.isEligible and eligibility.location.isEligible and eligibility.riskFactors.isEligible" + }, + { + "id": "expr2", + "key": "denialReasons", + "value": "filter([eligibility.age.reason, eligibility.location.reason, eligibility.riskFactors.reason], # != 'Age requirements met' and # != 'Location requirements met' and # != 'Risk factor assessment passed')" + }, + { + "id": "expr3", + "key": "policyDecision", + "value": "{ 'approved': isEligible, 'reasons': denialReasons }" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "finalDetermination", + "name": "Final Determination", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "ageEligibility", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "ageEligibility", + "targetId": "locationEligibility", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "locationEligibility", + "targetId": "riskFactors", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "riskFactors", + "targetId": "finalDetermination", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/portfolio-risk-monitor.json b/test-data/graphs/portfolio-risk-monitor.json new file mode 100644 index 00000000..a5ac9ad8 --- /dev/null +++ b/test-data/graphs/portfolio-risk-monitor.json @@ -0,0 +1,588 @@ +{ + "tests": [ + { + "input": { + "customer": { + "id": "cust-78945", + "name": "John Smith", + "riskTolerance": "moderate", + "investmentHorizon": "long-term", + "preferences": { + "allowAutomaticAdjustments": true, + "alertThreshold": "moderate", + "communicationPreference": "email" + } + }, + "portfolio": { + "id": "port-12345", + "name": "Retirement Portfolio", + "totalValue": 750000, + "creationDate": "2019-05-12", + "lastRebalance": 95, + "volatility": 22.5, + "highRiskPercentage": 35, + "currentAllocation": { + "equity": 65, + "bonds": 25, + "cash": 10 + }, + "targetAllocation": { + "equity": 60, + "bonds": 35, + "cash": 5 + }, + "holdings": [ + { + "symbol": "VTI", + "category": "equity", + "percentage": 30, + "value": 225000 + }, + { + "symbol": "VXUS", + "category": "equity", + "percentage": 20, + "value": 150000 + }, + { + "symbol": "VGT", + "category": "equity", + "percentage": 15, + "value": 112500 + }, + { + "symbol": "BND", + "category": "bonds", + "percentage": 25, + "value": 187500 + }, + { + "symbol": "CASH", + "category": "cash", + "percentage": 10, + "value": 75000 + } + ] + }, + "market": { + "volatilityIndex": 28.5, + "trendPercentage": -12.5, + "interestRate": 3.75, + "sectorPerformance": { + "technology": -15.2, + "healthcare": -5.1, + "financials": -18.4, + "consumerStaples": -3.2, + "utilities": 1.5 + }, + "economicIndicators": { + "gdpGrowth": 0.8, + "inflation": 4.2, + "unemploymentRate": 4.1 + } + } + }, + "output": { + "action": "rebalance", + "outcome": { + "riskScore": 0.53, + "status": "rebalance_suggested", + "timestamp": "2025-08-19T16:55:02.078Z" + }, + "rebalanceDetails": { + "currentAllocation": { + "bonds": 25, + "cash": 10, + "equity": 65 + }, + "customerId": "cust-78945", + "date": "2025-08-19", + "driftPercentage": "5.0", + "message": "Rebalancing recommended: Portfolio has drifted 5.0% from target allocation.", + "portfolioId": "port-12345", + "riskCategory": "high", + "riskScore": 0.53, + "suggestedChanges": { + "bonds": 10, + "cash": -5, + "equity": -5 + }, + "targetAllocation": { + "bonds": 35, + "cash": 5, + "equity": 60 + } + } + } + } + ], + "nodes": [ + { + "id": "inputNode", + "name": "request", + "type": "inputNode", + "content": { + "schema": "" + }, + "position": { + "x": 110, + "y": 193.5 + } + }, + { + "id": "marketConditionsTable", + "name": "marketConditionsAssessment", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "_id": "rule1", + "i1-1": "> 30", + "i1-2": "< -15", + "o1-1": "'severe'", + "o1-2": "0.8", + "o1-3": "'Highly volatile market with significant downward trend'" + }, + { + "_id": "rule2", + "i1-1": "> 25", + "i1-2": "< -10", + "o1-1": "'high'", + "o1-2": "0.7", + "o1-3": "'Elevated volatility with substantial market decline'" + }, + { + "_id": "rule3", + "i1-1": "> 20", + "i1-2": "< -5", + "o1-1": "'moderate'", + "o1-2": "0.5", + "o1-3": "'Increased volatility with market decline'" + }, + { + "_id": "rule4", + "i1-1": "> 25", + "i1-2": "> 5", + "o1-1": "'neutral'", + "o1-2": "0.3", + "o1-3": "'High volatility but positive market trend'" + }, + { + "_id": "rule5", + "i1-1": "> 15", + "i1-2": "", + "o1-1": "'elevated'", + "o1-2": "0.4", + "o1-3": "'Elevated market volatility'" + }, + { + "_id": "rule6", + "i1-1": "", + "i1-2": "< -10", + "o1-1": "'negative'", + "o1-2": "0.6", + "o1-3": "'Significant market decline'" + }, + { + "_id": "rule7", + "i1-1": "", + "i1-2": "", + "o1-1": "'normal'", + "o1-2": "0.2", + "o1-3": "'Normal market conditions'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Market Volatility Index", + "field": "market.volatilityIndex" + }, + { + "id": "i1-2", + "name": "Market Trend Percent", + "field": "market.trendPercentage" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Market Condition", + "field": "assessment.marketCondition" + }, + { + "id": "o1-2", + "name": "Market Risk Factor", + "field": "assessment.marketRiskFactor" + }, + { + "id": "o1-3", + "name": "Market Assessment", + "field": "assessment.marketAssessment" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 430, + "y": 193.5 + } + }, + { + "id": "portfolioExposureTable", + "name": "portfolioExposureAssessment", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "_id": "rule1", + "i1-1": "> 50", + "i1-2": "assessment.marketCondition == 'severe' or assessment.marketCondition == 'high'", + "o1-1": "'critical'", + "o1-2": "0.9" + }, + { + "_id": "rule2", + "i1-1": "> 40", + "i1-2": "assessment.marketCondition == 'severe' or assessment.marketCondition == 'high'", + "o1-1": "'high'", + "o1-2": "0.7" + }, + { + "_id": "rule3", + "i1-1": "> 30", + "i1-2": "assessment.marketCondition != 'normal'", + "o1-1": "'elevated'", + "o1-2": "0.5" + }, + { + "_id": "rule4", + "i1-1": "> 20", + "i1-2": "", + "o1-1": "'moderate'", + "o1-2": "0.3" + }, + { + "_id": "rule5", + "i1-1": "", + "i1-2": "", + "o1-1": "'low'", + "o1-2": "0.1" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "High-Risk Asset Percentage", + "field": "portfolio.highRiskPercentage" + }, + { + "id": "i1-2", + "name": "Market Condition Check" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Exposure Level", + "field": "assessment.exposureLevel" + }, + { + "id": "o1-2", + "name": "Exposure Factor", + "field": "assessment.exposureFactor" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 750, + "y": 193.5 + } + }, + { + "id": "portfolioVolatilityTable", + "name": "portfolioVolatilityAssessment", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "_id": "rule1", + "i1-1": "> 30", + "i1-2": "> 0.6", + "o1-1": "'high'", + "o1-2": "0.8" + }, + { + "_id": "rule2", + "i1-1": "> 25", + "i1-2": "> 0.4", + "o1-1": "'elevated'", + "o1-2": "0.6" + }, + { + "_id": "rule3", + "i1-1": "> 20", + "i1-2": "", + "o1-1": "'moderate'", + "o1-2": "0.4" + }, + { + "_id": "rule4", + "i1-1": "> 15", + "i1-2": "", + "o1-1": "'low'", + "o1-2": "0.2" + }, + { + "_id": "rule5", + "i1-1": "", + "i1-2": "", + "o1-1": "'minimal'", + "o1-2": "0.1" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Portfolio Volatility", + "field": "portfolio.volatility" + }, + { + "id": "i1-2", + "name": "Market Risk Factor", + "field": "assessment.marketRiskFactor" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Volatility Level", + "field": "assessment.volatilityLevel" + }, + { + "id": "o1-2", + "name": "Volatility Factor", + "field": "assessment.volatilityFactor" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 1070, + "y": 193.5 + } + }, + { + "id": "riskScoreCalculation", + "name": "calculateRiskScore", + "type": "expressionNode", + "content": { + "inputField": null, + "outputPath": null, + "expressions": [ + { + "id": "expr1", + "key": "marketWeight", + "value": "0.3" + }, + { + "id": "expr2", + "key": "exposureWeight", + "value": "0.4" + }, + { + "id": "expr3", + "key": "volatilityWeight", + "value": "0.3" + }, + { + "id": "expr4", + "key": "riskScore", + "value": "assessment.marketRiskFactor * $.marketWeight + assessment.exposureFactor * $.exposureWeight + assessment.volatilityFactor * $.volatilityWeight" + }, + { + "id": "expr5", + "key": "portfolioDrift", + "value": "abs(portfolio.currentAllocation.equity - portfolio.targetAllocation.equity)" + }, + { + "id": "expr6", + "key": "riskCategory", + "value": "$.riskScore >= 0.7 ? 'critical' : $.riskScore >= 0.5 ? 'high' : $.riskScore >= 0.3 ? 'moderate' : 'low'" + } + ], + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 1390, + "y": 193.5 + } + }, + { + "id": "actionDeterminationSwitch", + "name": "determineAction", + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "alertAction", + "condition": "riskCategory == 'moderate' and assessment.marketCondition != 'normal'", + "isDefault": false + }, + { + "id": "rebalanceAction", + "condition": "portfolioDrift > 10 or (riskCategory == 'high' and portfolio.lastRebalance > 90)", + "isDefault": false + }, + { + "id": "mitigateAction", + "condition": "riskCategory == 'critical' or (riskCategory == 'high' and assessment.marketCondition == 'severe')", + "isDefault": false + }, + { + "id": "noAction", + "condition": "", + "isDefault": true + } + ] + }, + "position": { + "x": 1710, + "y": 193.5 + } + }, + { + "id": "alertFunction", + "name": "generateAlert", + "type": "functionNode", + "content": { + "source": "import dayjs from 'dayjs';\nexport const handler = async (input) => {\n const { customer, portfolio, assessment, riskScore, riskCategory } = input;\n const alertDate = dayjs().format('YYYY-MM-DD');\n\n return {\n action: 'alert',\n alertDetails: {\n customerId: customer.id,\n portfolioId: portfolio.id,\n date: alertDate,\n riskScore: riskScore,\n riskCategory: riskCategory,\n message: `Risk alert: Portfolio risk level is ${riskCategory} (${riskScore.toFixed(2)}). Market conditions: ${assessment.marketAssessment}`,\n recommendedAction: 'Review portfolio allocation'\n },\n outcome: { status: 'alert_generated', riskScore: riskScore, timestamp: new Date().toISOString() }\n };\n};" + }, + "position": { + "x": 2030, + "y": 46.5 + } + }, + { + "id": "rebalanceFunction", + "name": "suggestRebalancing", + "type": "functionNode", + "content": { + "source": "import dayjs from 'dayjs';\nexport const handler = async (input) => {\n const { customer, portfolio, assessment, riskScore, riskCategory, portfolioDrift } = input;\n const currentDate = dayjs().format('YYYY-MM-DD');\n const suggestedEquity = portfolio.targetAllocation.equity;\n const suggestedBonds = portfolio.targetAllocation.bonds;\n const suggestedCash = portfolio.targetAllocation.cash;\n const driftPercentage = portfolioDrift.toFixed(1);\n\n return {\n action: 'rebalance',\n rebalanceDetails: {\n customerId: customer.id,\n portfolioId: portfolio.id,\n date: currentDate,\n riskScore: riskScore,\n riskCategory: riskCategory,\n currentAllocation: portfolio.currentAllocation,\n targetAllocation: portfolio.targetAllocation,\n driftPercentage: driftPercentage,\n suggestedChanges: {\n equity: suggestedEquity - portfolio.currentAllocation.equity,\n bonds: suggestedBonds - portfolio.currentAllocation.bonds,\n cash: suggestedCash - portfolio.currentAllocation.cash\n },\n message: `Rebalancing recommended: Portfolio has drifted ${driftPercentage}% from target allocation.`\n },\n outcome: { status: 'rebalance_suggested', riskScore: riskScore, timestamp: new Date().toISOString() }\n };\n};" + }, + "position": { + "x": 2030, + "y": 144.5 + } + }, + { + "id": "mitigationFunction", + "name": "implementRiskMitigation", + "type": "functionNode", + "content": { + "source": "import dayjs from 'dayjs';\nexport const handler = async (input) => {\n const { customer, portfolio, assessment, riskScore, riskCategory } = input;\n const mitigationDate = dayjs().format('YYYY-MM-DD');\n const suggestedEquity = Math.max(portfolio.targetAllocation.equity - 15, 0);\n const suggestedBonds = Math.min(portfolio.targetAllocation.bonds + 10, 100 - suggestedEquity - 5);\n const suggestedCash = 100 - suggestedEquity - suggestedBonds;\n\n return {\n action: 'mitigate',\n mitigationDetails: {\n customerId: customer.id,\n portfolioId: portfolio.id,\n date: mitigationDate,\n riskScore: riskScore,\n riskCategory: riskCategory,\n currentAllocation: portfolio.currentAllocation,\n suggestedAllocation: { equity: suggestedEquity, bonds: suggestedBonds, cash: suggestedCash },\n message: `Risk mitigation required: Market conditions (${assessment.marketCondition}) and portfolio risk (${riskCategory}) indicate immediate action needed.`,\n automaticChanges: assessment.marketCondition === 'severe' && riskCategory === 'critical' && customer.preferences.allowAutomaticAdjustments\n },\n outcome: { status: 'mitigation_implemented', riskScore: riskScore, timestamp: new Date().toISOString() }\n };\n};" + }, + "position": { + "x": 2030, + "y": 242.5 + } + }, + { + "id": "noActionRequired", + "name": "noActionNeeded", + "type": "expressionNode", + "content": { + "inputField": null, + "outputPath": null, + "expressions": [ + { + "id": "expr1", + "key": "outcome", + "value": "{ status: 'no_action_required', riskScore: riskScore, timestamp: string(date('now')) }" + } + ], + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 2030, + "y": 340.5 + } + } + ], + "edges": [ + { + "id": "edge1", + "type": "edge", + "sourceId": "inputNode", + "targetId": "marketConditionsTable" + }, + { + "id": "edge2", + "type": "edge", + "sourceId": "marketConditionsTable", + "targetId": "portfolioExposureTable" + }, + { + "id": "edge3", + "type": "edge", + "sourceId": "portfolioExposureTable", + "targetId": "portfolioVolatilityTable" + }, + { + "id": "edge4", + "type": "edge", + "sourceId": "portfolioVolatilityTable", + "targetId": "riskScoreCalculation" + }, + { + "id": "edge5", + "type": "edge", + "sourceId": "riskScoreCalculation", + "targetId": "actionDeterminationSwitch" + }, + { + "id": "edge6", + "type": "edge", + "sourceId": "actionDeterminationSwitch", + "targetId": "alertFunction", + "sourceHandle": "alertAction" + }, + { + "id": "edge7", + "type": "edge", + "sourceId": "actionDeterminationSwitch", + "targetId": "rebalanceFunction", + "sourceHandle": "rebalanceAction" + }, + { + "id": "edge8", + "type": "edge", + "sourceId": "actionDeterminationSwitch", + "targetId": "mitigationFunction", + "sourceHandle": "mitigateAction" + }, + { + "id": "edge9", + "type": "edge", + "sourceId": "actionDeterminationSwitch", + "targetId": "noActionRequired", + "sourceHandle": "noAction" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/preventive-care-recommendation.json b/test-data/graphs/preventive-care-recommendation.json new file mode 100644 index 00000000..079bed42 --- /dev/null +++ b/test-data/graphs/preventive-care-recommendation.json @@ -0,0 +1,370 @@ +{ + "tests": [ + { + "input": { + "firstName": "Jane", + "lastName": "Smith", + "age": 42, + "sex": "female", + "familyHistory": [ + "breast cancer", + "diabetes" + ], + "riskFactors": [ + "smoking" + ], + "lastCheckup": "2023-10-15" + }, + "output": { + "patientName": "Jane Smith", + "recommendationDate": "2025-08-19 16:55:02", + "summarizedRecommendations": [ + { + "genderBasedRecommendations": { + "primary": "Mammogram every 1-2 years (discuss with doctor)", + "secondary": "Cervical cancer screening every 3 years" + } + }, + { + "ageBasedRecommendations": { + "primary": "Blood pressure screening", + "quaternary": "Eye exam every 2-4 years", + "secondary": "Cholesterol screening every 5 years", + "tertiary": "Diabetes screening every 3 years" + } + }, + { + "riskBasedRecommendations": "Earlier and more frequent diabetes screening" + }, + { + "riskBasedRecommendations": "Earlier and more frequent mammograms" + }, + { + "riskBasedRecommendations": "Lung cancer screening" + } + ], + "totalRecommendations": 5 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "patientData", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "age1", + "i1": "< 18", + "o1": "\"Annual physical examination\"", + "o2": "\"Immunizations as per schedule\"", + "o3": "\"Vision screening\"", + "o4": "\"Dental checkup every 6 months\"" + }, + { + "_id": "age2", + "i1": ">= 18 and < 40", + "o1": "\"Blood pressure screening\"", + "o2": "\"Cholesterol screening every 5 years\"", + "o3": "\"Depression screening\"", + "o4": "\"Skin cancer screening\"" + }, + { + "_id": "age3", + "i1": ">= 40 and < 50", + "o1": "\"Blood pressure screening\"", + "o2": "\"Cholesterol screening every 5 years\"", + "o3": "\"Diabetes screening every 3 years\"", + "o4": "\"Eye exam every 2-4 years\"" + }, + { + "_id": "age4", + "i1": ">= 50 and < 65", + "o1": "\"Blood pressure screening\"", + "o2": "\"Cholesterol screening annually\"", + "o3": "\"Diabetes screening every 3 years\"", + "o4": "\"Colorectal cancer screening\"" + }, + { + "_id": "age5", + "i1": ">= 65", + "o1": "\"Blood pressure screening\"", + "o2": "\"Cholesterol screening annually\"", + "o3": "\"Diabetes screening annually\"", + "o4": "\"Fall risk assessment\"" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Age", + "field": "age" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Recommendation1", + "field": "recommendations.ageBasedRecommendations.primary" + }, + { + "id": "o2", + "name": "Recommendation2", + "field": "recommendations.ageBasedRecommendations.secondary" + }, + { + "id": "o3", + "name": "Recommendation3", + "field": "recommendations.ageBasedRecommendations.tertiary" + }, + { + "id": "o4", + "name": "Recommendation4", + "field": "recommendations.ageBasedRecommendations.quaternary" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "recommendations.age", + "executionMode": "single", + "passThorough": false + }, + "id": "ageSpecificScreenings", + "name": "ageBasedRecommendations", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "gender1", + "i1": "'female'", + "i2": "[21..30)", + "o1": "\"Cervical cancer screening every 3 years\"", + "o2": "\"Chlamydia screening annually (if sexually active)\"" + }, + { + "_id": "gender2", + "i1": "'female'", + "i2": "[30..40)", + "o1": "\"Cervical cancer screening every 3 years\"", + "o2": "\"HPV testing every 5 years\"" + }, + { + "_id": "gender3", + "i1": "'female'", + "i2": "[40..50)", + "o1": "\"Mammogram every 1-2 years (discuss with doctor)\"", + "o2": "\"Cervical cancer screening every 3 years\"" + }, + { + "_id": "gender4", + "i1": "'female'", + "i2": "[50..75)", + "o1": "\"Mammogram every 2 years\"", + "o2": "\"Bone density screening (65+ or at risk)\"" + }, + { + "_id": "gender5", + "i1": "'male'", + "i2": "[40..55)", + "o1": "\"Prostate health discussion with doctor\"", + "o2": "\"Testicular exam\"" + }, + { + "_id": "gender6", + "i1": "'male'", + "i2": "[55..70)", + "o1": "\"Prostate cancer screening (discuss with doctor)\"", + "o2": "\"Abdominal aortic aneurysm screening (if ever smoked)\"" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Sex", + "field": "sex" + }, + { + "id": "i2", + "name": "Age", + "field": "age" + } + ], + "outputs": [ + { + "id": "o1", + "name": "GenderRecommendation1", + "field": "recommendations.genderBasedRecommendations.primary" + }, + { + "id": "o2", + "name": "GenderRecommendation2", + "field": "recommendations.genderBasedRecommendations.secondary" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "recommendations.sex", + "executionMode": "single" + }, + "id": "genderSpecificScreenings", + "name": "sexBasedRecommendations", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "risk1", + "i1": "contains(familyHistory, \"diabetes\")", + "o1": "\"Earlier and more frequent diabetes screening\"" + }, + { + "_id": "risk2", + "i1": "contains(familyHistory, \"heart disease\")", + "o1": "\"Earlier and more frequent cholesterol and blood pressure monitoring\"" + }, + { + "_id": "risk3", + "i1": "contains(familyHistory, \"colorectal cancer\")", + "o1": "\"Earlier colorectal cancer screening (before age 45)\"" + }, + { + "_id": "risk4", + "i1": "contains(familyHistory, \"breast cancer\")", + "o1": "\"Earlier and more frequent mammograms\"" + }, + { + "_id": "risk5", + "i1": "contains(riskFactors, \"smoking\")", + "o1": "\"Lung cancer screening\"" + }, + { + "_id": "risk6", + "i1": "contains(riskFactors, \"obesity\")", + "o1": "\"More frequent diabetes and heart disease screenings\"" + }, + { + "_id": "risk7", + "i1": "contains(riskFactors, \"alcohol abuse\")", + "o1": "\"Liver function tests\"" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Risk Assessment" + } + ], + "outputs": [ + { + "id": "o1", + "name": "RiskRecommendation", + "field": "recommendations.riskBasedRecommendations" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "recommendations.risk", + "executionMode": "single" + }, + "id": "riskFactorScreenings", + "name": "riskBasedRecommendations", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "summarizedRecommendations", + "value": "flatMap(flatten(values(recommendations)), #.recommendations)" + }, + { + "id": "expr3", + "key": "patientName", + "value": "`${firstName} ${lastName}`" + }, + { + "id": "expr4", + "key": "recommendationDate", + "value": "dateString(date(\"now\"))" + }, + { + "id": "expr5", + "key": "totalRecommendations", + "value": "len($.summarizedRecommendations)" + }, + { + "id": "27928cee-be10-4e77-8089-f4ca14541539", + "key": "testResults", + "value": "null" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "generateRecommendations", + "name": "finalRecommendations", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "ageSpecificScreenings", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "ageSpecificScreenings", + "targetId": "genderSpecificScreenings", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "genderSpecificScreenings", + "targetId": "riskFactorScreenings", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "riskFactorScreenings", + "targetId": "generateRecommendations", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/product-listing-scoring.json b/test-data/graphs/product-listing-scoring.json new file mode 100644 index 00000000..f3ee169d --- /dev/null +++ b/test-data/graphs/product-listing-scoring.json @@ -0,0 +1,358 @@ +{ + "tests": [ + { + "input": { + "listing": { + "images": { + "count": 4, + "highResolution": true, + "hasVariantImages": true + }, + "description": { + "wordCount": 250, + "hasBulletPoints": true, + "hasSpecifications": true, + "keywordDensity": 3.2 + }, + "pricing": { + "competitiveRank": 2, + "hasDiscount": true + }, + "inventory": { + "stockLevel": 15, + "daysToShip": 2 + } + } + }, + "output": { + "breakdown": { + "descriptionCompleteness": { + "category": "good", + "score": 25 + }, + "imageQuality": { + "category": "good", + "score": 25 + }, + "inventoryAvailability": { + "score": 8 + }, + "keywordOptimization": { + "score": 15 + }, + "pricingCompetitiveness": { + "score": 8 + } + }, + "maximumPossibleScore": 100, + "overallScoreCategory": "excellent", + "totalScore": 81 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"listing\": {\n \"type\": \"object\",\n \"properties\": {\n \"images\": {\n \"type\": \"object\",\n \"properties\": {\n \"count\": {\"type\": \"integer\"},\n \"highResolution\": {\"type\": \"boolean\"},\n \"hasVariantImages\": {\"type\": \"boolean\"}\n }\n },\n \"description\": {\n \"type\": \"object\",\n \"properties\": {\n \"wordCount\": {\"type\": \"integer\"},\n \"hasBulletPoints\": {\"type\": \"boolean\"},\n \"hasSpecifications\": {\"type\": \"boolean\"},\n \"keywordDensity\": {\"type\": \"number\"}\n }\n },\n \"pricing\": {\n \"type\": \"object\",\n \"properties\": {\n \"competitiveRank\": {\"type\": \"integer\"},\n \"hasDiscount\": {\"type\": \"boolean\"}\n }\n },\n \"inventory\": {\n \"type\": \"object\",\n \"properties\": {\n \"stockLevel\": {\"type\": \"integer\"},\n \"daysToShip\": {\"type\": \"integer\"}\n }\n }\n }\n }\n }\n}" + }, + "id": "input-node", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "img-rule-1", + "imageCount": ">= 5", + "highRes": "true", + "hasVariantImages": "true", + "imgScore": "30", + "imgCategory": "'excellent'" + }, + { + "_id": "img-rule-2", + "imageCount": ">= 3", + "highRes": "true", + "hasVariantImages": "", + "imgScore": "25", + "imgCategory": "'good'" + }, + { + "_id": "img-rule-3", + "imageCount": ">= 2", + "highRes": "true", + "hasVariantImages": "", + "imgScore": "20", + "imgCategory": "'average'" + }, + { + "_id": "img-rule-4", + "imageCount": ">= 1", + "highRes": "", + "hasVariantImages": "", + "imgScore": "10", + "imgCategory": "'poor'" + }, + { + "_id": "img-rule-5", + "imageCount": "", + "highRes": "", + "hasVariantImages": "", + "imgScore": "0", + "imgCategory": "'missing'" + } + ], + "inputs": [ + { + "id": "imageCount", + "name": "Image Count", + "field": "listing.images.count" + }, + { + "id": "highRes", + "name": "High Resolution", + "field": "listing.images.highResolution" + }, + { + "id": "hasVariantImages", + "name": "Has Variant Images", + "field": "listing.images.hasVariantImages" + } + ], + "outputs": [ + { + "id": "imgScore", + "name": "Image Score", + "field": "scores.imageQuality.score" + }, + { + "id": "imgCategory", + "name": "Image Category", + "field": "scores.imageQuality.category" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "image-quality-node", + "name": "imageQuality", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "desc-rule-1", + "wordCount": "> 300", + "hasBullets": "true", + "hasSpecs": "true", + "keywordDensity": "> 2 and < 5", + "stockLevel": "> 20", + "competitiveRank": "< 3", + "descScore": "30", + "keywordScore": "20", + "inventoryScore": "10", + "pricingScore": "10", + "category": "'excellent'" + }, + { + "_id": "desc-rule-2", + "wordCount": "> 200", + "hasBullets": "true", + "hasSpecs": "", + "keywordDensity": "> 1 and < 6", + "stockLevel": "> 10", + "competitiveRank": "< 5", + "descScore": "25", + "keywordScore": "15", + "inventoryScore": "8", + "pricingScore": "8", + "category": "'good'" + }, + { + "_id": "desc-rule-3", + "wordCount": "> 100", + "hasBullets": "", + "hasSpecs": "", + "keywordDensity": "> 0", + "stockLevel": "> 5", + "competitiveRank": "< 10", + "descScore": "15", + "keywordScore": "10", + "inventoryScore": "5", + "pricingScore": "5", + "category": "'average'" + }, + { + "_id": "desc-rule-4", + "wordCount": "> 50", + "hasBullets": "", + "hasSpecs": "", + "keywordDensity": "", + "stockLevel": "> 0", + "competitiveRank": "", + "descScore": "10", + "keywordScore": "5", + "inventoryScore": "3", + "pricingScore": "3", + "category": "'poor'" + }, + { + "_id": "desc-rule-5", + "wordCount": "", + "hasBullets": "", + "hasSpecs": "", + "keywordDensity": "", + "stockLevel": "", + "competitiveRank": "", + "descScore": "0", + "keywordScore": "0", + "inventoryScore": "0", + "pricingScore": "0", + "category": "'missing'" + } + ], + "inputs": [ + { + "id": "wordCount", + "name": "Word Count", + "field": "listing.description.wordCount" + }, + { + "id": "hasBullets", + "name": "Has Bullet Points", + "field": "listing.description.hasBulletPoints" + }, + { + "id": "hasSpecs", + "name": "Has Specifications", + "field": "listing.description.hasSpecifications" + }, + { + "id": "keywordDensity", + "name": "Keyword Density", + "field": "listing.description.keywordDensity" + }, + { + "id": "stockLevel", + "name": "Stock Level", + "field": "listing.inventory.stockLevel" + }, + { + "id": "competitiveRank", + "name": "Competitive Rank", + "field": "listing.pricing.competitiveRank" + } + ], + "outputs": [ + { + "id": "descScore", + "name": "Description Score", + "field": "scores.descriptionCompleteness.score" + }, + { + "id": "keywordScore", + "name": "Keyword Score", + "field": "scores.keywordOptimization.score" + }, + { + "id": "inventoryScore", + "name": "Inventory Score", + "field": "scores.inventoryAvailability.score" + }, + { + "id": "pricingScore", + "name": "Pricing Score", + "field": "scores.pricingCompetitiveness.score" + }, + { + "id": "category", + "name": "Category", + "field": "scores.descriptionCompleteness.category" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "description-node", + "name": "descriptionAndOtherFactors", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr-1", + "key": "totalScore", + "value": "scores.imageQuality.score + scores.descriptionCompleteness.score + scores.keywordOptimization.score + scores.inventoryAvailability.score + scores.pricingCompetitiveness.score" + }, + { + "id": "expr-2", + "key": "overallScoreCategory", + "value": "$.totalScore >= 80 ? 'excellent' : $.totalScore >= 60 ? 'good' : $.totalScore >= 40 ? 'average' : $.totalScore >= 20 ? 'poor' : 'unacceptable'" + }, + { + "id": "a3ffe24e-36ba-48a8-9f07-d77bdcbbdfe0", + "key": "maximumPossibleScore", + "value": "100" + }, + { + "id": "expr-3", + "key": "breakdown", + "value": "{\n 'imageQuality': scores.imageQuality,\n 'descriptionCompleteness': scores.descriptionCompleteness,\n 'keywordOptimization': scores.keywordOptimization,\n 'inventoryAvailability': scores.inventoryAvailability,\n 'pricingCompetitiveness': scores.pricingCompetitiveness\n}" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "overall-score-node", + "name": "overallScore", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge-input-to-image", + "sourceId": "input-node", + "targetId": "image-quality-node", + "type": "edge" + }, + { + "id": "edge-image-to-description", + "sourceId": "image-quality-node", + "targetId": "description-node", + "type": "edge" + }, + { + "id": "edge-description-to-overall", + "sourceId": "description-node", + "targetId": "overall-score-node", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/realtime-fraud-detection.json b/test-data/graphs/realtime-fraud-detection.json new file mode 100644 index 00000000..7ee1c9ee --- /dev/null +++ b/test-data/graphs/realtime-fraud-detection.json @@ -0,0 +1,235 @@ +{ + "tests": [ + { + "input": { + "transaction": { + "id": "tx-28473", + "amount": 1250, + "location": "Germany", + "time": "23:45", + "recentCount": 4, + "merchantCategory": "Electronics", + "date": "2023-03-18" + }, + "userProfile": { + "id": "user-5932", + "homeCountry": "USA", + "frequentCountries": [ + "Canada", + "UK" + ], + "averageTransactionAmount": 350, + "maxTransactionAmount": 800, + "usualMerchantCategories": [ + "Groceries", + "Dining", + "Retail" + ], + "usualTransactionTimeRange": [ + "08:00", + "21:00" + ] + } + }, + "output": { + "blockTransaction": false, + "finalRiskScore": 75, + "reason": "Unusual location with amount significantly above average", + "requiresReview": true + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "locationInput": "!= userProfile.homeCountry and != userProfile.frequentCountries", + "amountInput": "> userProfile.averageTransactionAmount * 3", + "timeInput": "", + "frequencyInput": "", + "outputRisk": "75", + "outputFlag": "'high'", + "outputReason": "'Unusual location with amount significantly above average'" + }, + { + "_id": "rule2", + "locationInput": "!= userProfile.homeCountry", + "amountInput": "> userProfile.averageTransactionAmount * 2", + "timeInput": "time($) > time('22:00') and time($) < time('06:00')", + "frequencyInput": "", + "outputRisk": "65", + "outputFlag": "'high'", + "outputReason": "'Foreign transaction at night with high value'" + }, + { + "_id": "rule3", + "locationInput": "", + "amountInput": "> userProfile.averageTransactionAmount * 4", + "timeInput": "", + "frequencyInput": "> 3", + "outputRisk": "80", + "outputFlag": "'high'", + "outputReason": "'Multiple high-value transactions in short timeframe'" + }, + { + "_id": "rule4", + "locationInput": "!= userProfile.homeCountry", + "amountInput": "", + "timeInput": "", + "frequencyInput": "> 5", + "outputRisk": "70", + "outputFlag": "'high'", + "outputReason": "'Multiple foreign transactions in short timeframe'" + }, + { + "_id": "rule5", + "locationInput": "", + "amountInput": "> userProfile.averageTransactionAmount * 2", + "timeInput": "time($) > time('22:00') and time($) < time('06:00')", + "frequencyInput": "", + "outputRisk": "50", + "outputFlag": "'medium'", + "outputReason": "'Night transaction with amount above average'" + }, + { + "_id": "rule6", + "locationInput": "", + "amountInput": "", + "timeInput": "", + "frequencyInput": "> 3", + "outputRisk": "45", + "outputFlag": "'medium'", + "outputReason": "'Multiple transactions in short timeframe'" + }, + { + "_id": "rule7", + "locationInput": "", + "amountInput": "", + "timeInput": "", + "frequencyInput": "", + "outputRisk": "0", + "outputFlag": "'low'", + "outputReason": "'No suspicious patterns detected'" + } + ], + "inputs": [ + { + "id": "locationInput", + "name": "Transaction Location", + "field": "transaction.location" + }, + { + "id": "amountInput", + "name": "Transaction Amount", + "field": "transaction.amount" + }, + { + "id": "timeInput", + "name": "Transaction Time", + "field": "transaction.time" + }, + { + "id": "frequencyInput", + "name": "Recent Transactions Count", + "field": "transaction.recentCount" + } + ], + "outputs": [ + { + "id": "outputRisk", + "name": "Risk Score", + "field": "fraud.riskScore" + }, + { + "id": "outputFlag", + "name": "Risk Flag", + "field": "fraud.flag" + }, + { + "id": "outputReason", + "name": "Risk Reason", + "field": "fraud.reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "fraudDetection", + "name": "detectSuspiciousActivity", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "finalRiskScore", + "value": "number(fraud.riskScore)" + }, + { + "id": "expr2", + "key": "requiresReview", + "value": "fraud.flag == 'high' or $.finalRiskScore > 60" + }, + { + "id": "expr3", + "key": "blockTransaction", + "value": "$.finalRiskScore > 75" + }, + { + "id": "expr4", + "key": "reason", + "value": "fraud.reason" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "riskScoring", + "name": "calculateRiskScore", + "position": { + "x": 750, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "fraudDetection", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "fraudDetection", + "targetId": "riskScoring", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/regional-compliance-manager.json b/test-data/graphs/regional-compliance-manager.json new file mode 100644 index 00000000..52f5066a --- /dev/null +++ b/test-data/graphs/regional-compliance-manager.json @@ -0,0 +1,278 @@ +{ + "tests": [ + { + "input": { + "customer": { + "id": "CUST-83921", + "region": "EU", + "type": "individual", + "consentProvided": true, + "age": 32, + "serviceLevel": "standard", + "dateJoined": "2023-05-15" + }, + "serviceRequest": { + "upgradeToPremium": true, + "internationalRoaming": true, + "dataSharing": false + } + }, + "output": { + "eligibility": { + "notes": "Age verification required for premium services", + "premiumServices": true + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "customerData", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "region": "'EU'", + "dataRetention": "24", + "privacyRequirements": "'GDPR'", + "consentRequired": "true", + "serviceRestrictions": "['roaming_cap', 'third_party_data_sharing']", + "exportAllowed": "false" + }, + { + "_id": "rule2", + "region": "'US'", + "dataRetention": "36", + "privacyRequirements": "'CCPA'", + "consentRequired": "true", + "serviceRestrictions": "['international_calls_verification']", + "exportAllowed": "true" + }, + { + "_id": "rule3", + "region": "'UK'", + "dataRetention": "24", + "privacyRequirements": "'UK_GDPR'", + "consentRequired": "true", + "serviceRestrictions": "['roaming_cap']", + "exportAllowed": "false" + }, + { + "_id": "rule4", + "region": "'CA'", + "dataRetention": "18", + "privacyRequirements": "'PIPEDA'", + "consentRequired": "true", + "serviceRestrictions": "[]", + "exportAllowed": "true" + }, + { + "_id": "rule5", + "region": "'AU'", + "dataRetention": "12", + "privacyRequirements": "'Privacy_Act'", + "consentRequired": "true", + "serviceRestrictions": "[]", + "exportAllowed": "true" + }, + { + "_id": "rule6", + "region": "", + "dataRetention": "36", + "privacyRequirements": "'default'", + "consentRequired": "false", + "serviceRestrictions": "[]", + "exportAllowed": "true" + } + ], + "inputs": [ + { + "id": "region", + "name": "Region", + "field": "customer.region" + } + ], + "outputs": [ + { + "id": "dataRetention", + "name": "Data Retention Period (months)", + "field": "compliance.dataRetentionMonths" + }, + { + "id": "privacyRequirements", + "name": "Privacy Framework", + "field": "compliance.privacyFramework" + }, + { + "id": "consentRequired", + "name": "Explicit Consent Required", + "field": "compliance.explicitConsentRequired" + }, + { + "id": "serviceRestrictions", + "name": "Service Restrictions", + "field": "compliance.serviceRestrictions" + }, + { + "id": "exportAllowed", + "name": "Data Export Allowed", + "field": "compliance.dataExportAllowed" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "regionRules", + "name": "regionalComplianceRules", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "complianceStatus", + "value": "compliance.explicitConsentRequired == true and customer.consentProvided == true ? 'compliant' : (compliance.explicitConsentRequired == false ? 'compliant' : 'non_compliant')" + }, + { + "id": "expr2", + "key": "dataRetentionDate", + "value": "date('now') + (number(compliance.dataRetentionMonths) * 30 * 24 * 60 * 60 * 1000)" + }, + { + "id": "expr3", + "key": "complianceSummary", + "value": "`Region: ${customer.region}, Framework: ${compliance.privacyFramework}, Retention: ${compliance.dataRetentionMonths} months`" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "complianceOutput", + "name": "complianceEvaluation", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "eligible1", + "customerType": "'business'", + "region": "'EU'", + "eligibleForPremium": "true", + "additionalNotes": "'Business customers in EU require additional data processing agreement'" + }, + { + "_id": "eligible2", + "customerType": "'business'", + "region": "", + "eligibleForPremium": "true", + "additionalNotes": "'Standard business customer requirements apply'" + }, + { + "_id": "eligible3", + "customerType": "'individual'", + "region": "'US', 'CA', 'AU'", + "eligibleForPremium": "true", + "additionalNotes": "'No additional requirements'" + }, + { + "_id": "eligible4", + "customerType": "'individual'", + "region": "'EU', 'UK'", + "eligibleForPremium": "customer.age >= 18", + "additionalNotes": "'Age verification required for premium services'" + }, + { + "_id": "eligible5", + "customerType": "", + "region": "", + "eligibleForPremium": "false", + "additionalNotes": "'Default ineligible until properly categorized'" + } + ], + "inputs": [ + { + "id": "customerType", + "name": "Customer Type", + "field": "customer.type" + }, + { + "id": "region", + "name": "Region", + "field": "customer.region" + } + ], + "outputs": [ + { + "id": "eligibleForPremium", + "name": "Eligible for Premium Services", + "field": "eligibility.premiumServices" + }, + { + "id": "additionalNotes", + "name": "Additional Notes", + "field": "eligibility.notes" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "additionalRestrictions", + "name": "serviceEligibility", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "regionRules", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "regionRules", + "targetId": "complianceOutput", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "complianceOutput", + "targetId": "additionalRestrictions", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/returns-and-refund-policy.json b/test-data/graphs/returns-and-refund-policy.json new file mode 100644 index 00000000..719f845c --- /dev/null +++ b/test-data/graphs/returns-and-refund-policy.json @@ -0,0 +1,366 @@ +{ + "tests": [ + { + "input": { + "orderInfo": { + "orderId": "ORD-12345", + "purchaseDate": "2023-10-15" + }, + "returnReason": "damaged", + "daysSincePurchase": 25, + "originalPrice": 89.99, + "itemCondition": "new", + "sellerPolicy": { + "returnsAllowed": true, + "returnWindow": 30, + "restockingFeePercent": 15, + "freeReturnShipping": false + }, + "buyerInfo": { + "id": "USR-789", + "returnHistory": { + "totalReturns": 3, + "recentDisputes": 0 + } + }, + "productDetails": { + "category": "electronics", + "isWarrantyActive": true + } + }, + "output": { + "buyerInfo": { + "id": "USR-789", + "returnHistory": { + "recentDisputes": 0, + "totalReturns": 3 + } + }, + "daysSincePurchase": 25, + "itemCondition": "new", + "orderInfo": { + "orderId": "ORD-12345", + "purchaseDate": "2023-10-15" + }, + "originalPrice": 89.99, + "processingTimeEstimate": 5, + "productDetails": { + "category": "electronics", + "isWarrantyActive": true + }, + "refundAmount": 89.99, + "refundShipping": true, + "resolution": { + "note": "Seller is responsible for product issues on new items.", + "refundApproved": true, + "responsibleParty": "seller" + }, + "returnReason": "damaged", + "returnShippingCovered": true, + "returnStatus": { + "code": "eligible", + "isEligible": true, + "message": "The return is within policy timeframe and eligible for processing." + }, + "sellerPolicy": { + "freeReturnShipping": false, + "restockingFeePercent": 15, + "returnWindow": 30, + "returnsAllowed": true + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "< 30", + "i1-2": "true", + "i1-3": "'damaged', 'defective', 'wrong_item'", + "o1-1": "true", + "o1-2": "'eligible'", + "o1-3": "'The return is within policy timeframe and eligible for processing.'" + }, + { + "_id": "r1-2", + "i1-1": "< 30", + "i1-2": "true", + "i1-3": "'changed_mind'", + "o1-1": "true", + "o1-2": "'eligible_restocking_fee'", + "o1-3": "'Return is eligible but subject to restocking fee per seller policy.'" + }, + { + "_id": "r1-3", + "i1-1": "> 30, <= 60", + "i1-2": "true", + "i1-3": "'damaged', 'defective'", + "o1-1": "true", + "o1-2": "'eligible_extended'", + "o1-3": "'Extended return period applies for product issues.'" + }, + { + "_id": "r1-4", + "i1-1": "> 60", + "i1-2": "", + "i1-3": "", + "o1-1": "false", + "o1-2": "'ineligible_timeframe'", + "o1-3": "'Return period has expired.'" + }, + { + "_id": "r1-5", + "i1-1": "", + "i1-2": "false", + "i1-3": "", + "o1-1": "false", + "o1-2": "'ineligible_non_returnable'", + "o1-3": "'Item is marked as non-returnable in seller policy.'" + }, + { + "_id": "r1-6", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "o1-1": "false", + "o1-2": "'ineligible_other'", + "o1-3": "'Return does not meet eligibility criteria.'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Days Since Purchase", + "field": "daysSincePurchase" + }, + { + "id": "i1-2", + "name": "Item Returnable", + "field": "sellerPolicy.returnsAllowed" + }, + { + "id": "i1-3", + "name": "Return Reason", + "field": "returnReason" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Is Eligible", + "field": "returnStatus.isEligible" + }, + { + "id": "o1-2", + "name": "Eligibility Code", + "field": "returnStatus.code" + }, + { + "id": "o1-3", + "name": "Eligibility Message", + "field": "returnStatus.message" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "returnEligibility", + "name": "returnEligibility", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'damaged', 'defective'", + "i2-2": "'new', 'like_new'", + "i2-3": "true", + "o2-1": "'seller'", + "o2-2": "true", + "o2-3": "'Seller is responsible for product issues on new items.'" + }, + { + "_id": "r2-2", + "i2-1": "'wrong_item'", + "i2-2": "", + "i2-3": "true", + "o2-1": "'seller'", + "o2-2": "true", + "o2-3": "'Seller is responsible for shipping incorrect item.'" + }, + { + "_id": "r2-3", + "i2-1": "'damaged_in_transit'", + "i2-2": "", + "i2-3": "true", + "o2-1": "'platform'", + "o2-2": "true", + "o2-3": "'Platform shipping protection covers transit damage.'" + }, + { + "_id": "r2-4", + "i2-1": "'changed_mind'", + "i2-2": "", + "i2-3": "true", + "o2-1": "'buyer'", + "o2-2": "true", + "o2-3": "'Buyer is responsible for return costs when changing mind.'" + }, + { + "_id": "r2-5", + "i2-1": "'damaged', 'defective'", + "i2-2": "'used', 'refurbished'", + "i2-3": "true", + "o2-1": "'shared'", + "o2-2": "true", + "o2-3": "'Responsibility is shared for used/refurbished items with issues.'" + }, + { + "_id": "r2-6", + "i2-1": "", + "i2-2": "", + "i2-3": "false", + "o2-1": "'none'", + "o2-2": "false", + "o2-3": "'No refund applicable for ineligible returns.'" + }, + { + "_id": "r2-7", + "i2-1": "", + "i2-2": "", + "i2-3": "", + "o2-1": "'platform'", + "o2-2": "false", + "o2-3": "'Platform will review the case for final determination.'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Return Reason", + "field": "returnReason" + }, + { + "id": "i2-2", + "name": "Item Condition", + "field": "itemCondition" + }, + { + "id": "i2-3", + "name": "Is Eligible", + "field": "returnStatus.isEligible" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Responsible Party", + "field": "resolution.responsibleParty" + }, + { + "id": "o2-2", + "name": "Refund Approved", + "field": "resolution.refundApproved" + }, + { + "id": "o2-3", + "name": "Responsibility Note", + "field": "resolution.note" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "responsibilityDetermination", + "name": "responsibilityDetermination", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "refundAmount", + "value": "resolution.refundApproved == true ? \n (returnStatus.code == 'eligible_restocking_fee' ? \n originalPrice * (1 - sellerPolicy.restockingFeePercent / 100) : \n originalPrice) : \n 0" + }, + { + "id": "e2", + "key": "refundShipping", + "value": "resolution.responsibleParty == 'seller' or resolution.responsibleParty == 'platform'" + }, + { + "id": "e3", + "key": "returnShippingCovered", + "value": "resolution.responsibleParty == 'seller' or resolution.responsibleParty == 'platform'" + }, + { + "id": "e4", + "key": "processingTimeEstimate", + "value": "resolution.refundApproved == true ? \n (resolution.responsibleParty == 'platform' ? 7 : \n resolution.responsibleParty == 'seller' ? 5 : 3) : \n 14" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "refundCalculation", + "name": "refundCalculation", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "returnEligibility", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "returnEligibility", + "targetId": "responsibilityDetermination", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "responsibilityDetermination", + "targetId": "refundCalculation", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/returns-processing-system.json b/test-data/graphs/returns-processing-system.json new file mode 100644 index 00000000..53777012 --- /dev/null +++ b/test-data/graphs/returns-processing-system.json @@ -0,0 +1,448 @@ +{ + "tests": [ + { + "input": { + "customer": { + "id": "CUST-12345", + "membershipTier": "premium", + "returnsHistoryCount": 3 + }, + "product": { + "type": "electronics", + "condition": "damaged", + "daysFromPurchase": 12, + "price": 249.99 + }, + "return": { + "reason": "defective item - won't power on", + "hasReceipt": true + } + }, + "output": { + "customer": { + "id": "CUST-12345", + "membershipTier": "premium", + "returnsHistoryCount": 3 + }, + "isFrequentReturner": false, + "isHighValueCustomer": true, + "isHighValueItem": true, + "isPurchaseWithinWarranty": true, + "product": { + "condition": "damaged", + "daysFromPurchase": 12, + "price": 249.99, + "type": "electronics" + }, + "return": { + "hasReceipt": true, + "reason": "defective item - won't power on" + }, + "returnDetails": { + "customerCommunication": "partial_approval", + "expectedProcessingDays": 2, + "priorityLevel": "high", + "processingQueue": "returns_dept", + "refundAmount": 199.992, + "restockingFee": 10, + "type": "partial_refund" + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"customer\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": { \"type\": \"string\" },\n \"membershipTier\": { \"type\": \"string\", \"enum\": [\"standard\", \"premium\", \"vip\"] },\n \"returnsHistoryCount\": { \"type\": \"integer\" }\n }\n },\n \"product\": {\n \"type\": \"object\",\n \"properties\": {\n \"type\": { \"type\": \"string\" },\n \"condition\": { \"type\": \"string\", \"enum\": [\"new\", \"like_new\", \"damaged\", \"opened\", \"used\"] },\n \"daysFromPurchase\": { \"type\": \"integer\" },\n \"price\": { \"type\": \"number\" }\n }\n },\n \"return\": {\n \"type\": \"object\",\n \"properties\": {\n \"reason\": { \"type\": \"string\" },\n \"hasReceipt\": { \"type\": \"boolean\" }\n }\n }\n }\n}\n" + }, + "id": "input1", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "isHighValueCustomer", + "value": "customer.membershipTier == 'vip' or customer.membershipTier == 'premium'" + }, + { + "id": "expr2", + "key": "isFrequentReturner", + "value": "customer.returnsHistoryCount > 5" + }, + { + "id": "expr3", + "key": "isPurchaseWithinWarranty", + "value": "product.daysFromPurchase <= 30" + }, + { + "id": "expr4", + "key": "isHighValueItem", + "value": "product.price >= 100" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "customerStatus", + "name": "customerEligibility", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "productType": "'electronics', 'appliances'", + "productCondition": "'new', 'like_new'", + "returnReason": "startsWith($, 'defect')", + "daysFromPurchase": "<= 30", + "hasReceipt": "true", + "returnType": "'warranty_replacement'", + "refundAmount": "product.price", + "restockingFee": "0" + }, + { + "_id": "rule2", + "productType": "'electronics', 'appliances'", + "productCondition": "'damaged', 'opened'", + "returnReason": "", + "daysFromPurchase": "<= 15", + "hasReceipt": "true", + "returnType": "'partial_refund'", + "refundAmount": "product.price * 0.8", + "restockingFee": "10" + }, + { + "_id": "rule3", + "productType": "'clothing', 'accessories'", + "productCondition": "'new', 'like_new'", + "returnReason": "", + "daysFromPurchase": "<= 30", + "hasReceipt": "true", + "returnType": "'full_refund'", + "refundAmount": "product.price", + "restockingFee": "0" + }, + { + "_id": "rule4", + "productType": "'clothing', 'accessories'", + "productCondition": "'used', 'opened'", + "returnReason": "", + "daysFromPurchase": "<= 15", + "hasReceipt": "true", + "returnType": "'store_credit'", + "refundAmount": "product.price * 0.7", + "restockingFee": "5" + }, + { + "_id": "rule5", + "productType": "", + "productCondition": "", + "returnReason": "contains($, 'quality')", + "daysFromPurchase": "<= 90", + "hasReceipt": "", + "returnType": "'quality_review'", + "refundAmount": "isHighValueCustomer ? product.price : product.price * 0.9", + "restockingFee": "0" + }, + { + "_id": "rule6", + "productType": "", + "productCondition": "", + "returnReason": "", + "daysFromPurchase": "> 30", + "hasReceipt": "false", + "returnType": "'store_credit'", + "refundAmount": "isHighValueCustomer ? product.price * 0.8 : product.price * 0.5", + "restockingFee": "isHighValueCustomer ? 0 : 15" + }, + { + "_id": "rule7", + "productType": "", + "productCondition": "", + "returnReason": "", + "daysFromPurchase": "> 90", + "hasReceipt": "", + "returnType": "'denied'", + "refundAmount": "0", + "restockingFee": "0" + }, + { + "_id": "rule8", + "productType": "", + "productCondition": "", + "returnReason": "", + "daysFromPurchase": "", + "hasReceipt": "", + "returnType": "'manual_review'", + "refundAmount": "0", + "restockingFee": "0" + } + ], + "inputs": [ + { + "id": "productType", + "name": "Product Type", + "field": "product.type" + }, + { + "id": "productCondition", + "name": "Product Condition", + "field": "product.condition" + }, + { + "id": "returnReason", + "name": "Return Reason", + "field": "return.reason" + }, + { + "id": "daysFromPurchase", + "name": "Days From Purchase", + "field": "product.daysFromPurchase" + }, + { + "id": "hasReceipt", + "name": "Has Receipt", + "field": "return.hasReceipt" + } + ], + "outputs": [ + { + "id": "returnType", + "name": "Return Type", + "field": "returnDetails.type" + }, + { + "id": "refundAmount", + "name": "Refund Amount", + "field": "returnDetails.refundAmount" + }, + { + "id": "restockingFee", + "name": "Restocking Fee", + "field": "returnDetails.restockingFee" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "returnsClassification", + "name": "determineReturnType", + "position": { + "x": 750, + "y": 115 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "queue1", + "returnType": "'warranty_replacement'", + "processingQueue": "'warranty_dept'" + }, + { + "_id": "queue2", + "returnType": "'quality_review'", + "processingQueue": "'quality_assurance'" + }, + { + "_id": "queue3", + "returnType": "'manual_review'", + "processingQueue": "'customer_service'" + }, + { + "_id": "queue4", + "returnType": "", + "processingQueue": "'returns_dept'" + } + ], + "inputs": [ + { + "id": "returnType", + "name": "Return Type", + "field": "returnDetails.type" + } + ], + "outputs": [ + { + "id": "processingQueue", + "name": "Processing Queue", + "field": "returnDetails.processingQueue" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "processingQueueTable", + "name": "determineProcessingQueue", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "priority1", + "highValueCustomer": "true", + "highValueItem": "", + "priorityLevel": "'high'", + "expectedProcessingDays": "2" + }, + { + "_id": "priority2", + "highValueCustomer": "false", + "highValueItem": "true", + "priorityLevel": "'medium'", + "expectedProcessingDays": "5" + }, + { + "_id": "priority3", + "highValueCustomer": "false", + "highValueItem": "false", + "priorityLevel": "'standard'", + "expectedProcessingDays": "7" + } + ], + "inputs": [ + { + "id": "highValueCustomer", + "name": "High Value Customer", + "field": "isHighValueCustomer" + }, + { + "id": "highValueItem", + "name": "High Value Item", + "field": "isHighValueItem" + } + ], + "outputs": [ + { + "id": "priorityLevel", + "name": "Priority Level", + "field": "returnDetails.priorityLevel" + }, + { + "id": "expectedProcessingDays", + "name": "Expected Processing Days", + "field": "returnDetails.expectedProcessingDays" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "priorityLevelTable", + "name": "determinePriorityLevel", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "comm1", + "returnType": "'denied'", + "customerCommunication": "'rejection_notice'" + }, + { + "_id": "comm2", + "returnType": "'partial_refund', 'store_credit'", + "customerCommunication": "'partial_approval'" + }, + { + "_id": "comm3", + "returnType": "", + "customerCommunication": "'approved'" + } + ], + "inputs": [ + { + "id": "returnType", + "name": "Return Type", + "field": "returnDetails.type" + } + ], + "outputs": [ + { + "id": "customerCommunication", + "name": "Customer Communication", + "field": "returnDetails.customerCommunication" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "communicationTable", + "name": "determineCommunication", + "position": { + "x": 1710, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input1", + "targetId": "customerStatus", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "customerStatus", + "targetId": "returnsClassification", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "returnsClassification", + "targetId": "processingQueueTable", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "processingQueueTable", + "targetId": "priorityLevelTable", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "priorityLevelTable", + "targetId": "communicationTable", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/school-district-resource-allocation.json b/test-data/graphs/school-district-resource-allocation.json new file mode 100644 index 00000000..55373e82 --- /dev/null +++ b/test-data/graphs/school-district-resource-allocation.json @@ -0,0 +1,282 @@ +{ + "tests": [ + { + "input": { + "school": { + "id": "sch_12345", + "name": "Washington High School", + "type": "secondary", + "student_population": 750, + "special_education_students": 45, + "esl_students": 80, + "gifted_students": 35, + "test_scores": { + "math": 82, + "reading": 78 + }, + "special_programs": [ + "special_education", + "esl", + "stem" + ] + } + }, + "output": { + "adjusted_funding": 4537500, + "allocation": { + "base_funding": 4125000, + "school_size": "medium" + }, + "funding": [ + { + "allocation": { + "funding_descriptions": "Special Education Support", + "program_funding": 135000 + } + }, + { + "allocation": { + "funding_descriptions": "ESL Program Support", + "program_funding": 200000 + } + }, + { + "allocation": { + "funding_descriptions": "STEM Program Support", + "program_funding": 20000 + } + } + ], + "performance_multiplier": 1.1, + "performance_score": 80, + "school": { + "esl_students": 80, + "gifted_students": 35, + "id": "sch_12345", + "name": "Washington High School", + "special_education_students": 45, + "special_programs": [ + "special_education", + "esl", + "stem" + ], + "student_population": 750, + "test_scores": { + "math": 82, + "reading": 78 + }, + "type": "secondary" + } + } + } + ], + "nodes": [ + { + "id": "inputNode", + "name": "request", + "type": "inputNode", + "content": { + "schema": "" + }, + "position": { + "x": 110, + "y": 114 + } + }, + { + "id": "baseAllocationTable", + "name": "baseAllocation", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "i1": "> 1000", + "i2": "", + "o1": "school.student_population * 5000", + "o2": "'large'", + "_id": "r1" + }, + { + "i1": "> 500", + "i2": "", + "o1": "school.student_population * 5500", + "o2": "'medium'", + "_id": "r2" + }, + { + "i1": "> 200", + "i2": "", + "o1": "school.student_population * 6000", + "o2": "'small'", + "_id": "r3" + }, + { + "i1": "", + "i2": "'elementary'", + "o1": "school.student_population * 6500", + "o2": "'very_small'", + "_id": "r4" + }, + { + "i1": "", + "i2": "", + "o1": "school.student_population * 6000", + "o2": "'very_small'", + "_id": "r5" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Student Population", + "field": "school.student_population" + }, + { + "id": "i2", + "name": "School Type", + "field": "school.type" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Base Funding", + "field": "allocation.base_funding" + }, + { + "id": "o2", + "name": "School Size Category", + "field": "allocation.school_size" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 430, + "y": 114 + } + }, + { + "id": "performanceAdjustment", + "name": "performanceAdjustment", + "type": "expressionNode", + "content": { + "inputField": null, + "outputPath": null, + "expressions": [ + { + "id": "e1", + "key": "performance_score", + "value": "(school.test_scores.math + school.test_scores.reading) / 2" + }, + { + "id": "e2", + "key": "performance_multiplier", + "value": "$.performance_score < 70 ? 1.2 : ($.performance_score < 85 ? 1.1 : 1.0)" + }, + { + "id": "e3", + "key": "adjusted_funding", + "value": "allocation.base_funding * $.performance_multiplier" + } + ], + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 750, + "y": 114 + } + }, + { + "id": "specialProgramsTable", + "name": "specialProgramsAdjustment", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "i1": "contains(school.special_programs, 'special_education')", + "o1": "school.special_education_students * 3000", + "o2": "'Special Education Support'", + "_id": "sp1" + }, + { + "i1": "contains(school.special_programs, 'esl')", + "o1": "school.esl_students * 2500", + "o2": "'ESL Program Support'", + "_id": "sp2" + }, + { + "i1": "contains(school.special_programs, 'gifted')", + "o1": "school.gifted_students * 1800", + "o2": "'Gifted Program Support'", + "_id": "sp3" + }, + { + "i1": "contains(school.special_programs, 'stem')", + "o1": "20000", + "o2": "'STEM Program Support'", + "_id": "sp4" + }, + { + "i1": "contains(school.special_programs, 'arts')", + "o1": "15000", + "o2": "'Arts Program Support'", + "_id": "sp5" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Special Programs" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Additional Funding", + "field": "allocation.program_funding" + }, + { + "id": "o2", + "name": "Funding Description", + "field": "allocation.funding_descriptions" + } + ], + "hitPolicy": "collect", + "inputField": null, + "outputPath": "funding", + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "e1", + "type": "edge", + "sourceId": "inputNode", + "targetId": "baseAllocationTable" + }, + { + "id": "e2", + "type": "edge", + "sourceId": "baseAllocationTable", + "targetId": "performanceAdjustment" + }, + { + "id": "e3", + "type": "edge", + "sourceId": "performanceAdjustment", + "targetId": "specialProgramsTable" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/seat-map-optimization.json b/test-data/graphs/seat-map-optimization.json new file mode 100644 index 00000000..553b5aca --- /dev/null +++ b/test-data/graphs/seat-map-optimization.json @@ -0,0 +1,325 @@ +{ + "tests": [ + { + "input": { + "customer": { + "id": "CUS123456", + "tier": "gold", + "fareClass": "economy_plus", + "groupSize": 3, + "hasSpecialNeeds": false, + "previousFlights": 24 + }, + "cabin": { + "id": "CAB789", + "name": "main cabin", + "totalSeats": 180, + "occupiedSeats": 108, + "premiumSeats": 32, + "standardSeats": 138, + "restrictedSeats": 10 + }, + "flight": { + "flightNumber": "FL722", + "departureTime": "2025-04-15T08:30:00Z", + "arrivalTime": "2025-04-15T11:45:00Z", + "aircraft": "Boeing 737-800" + } + }, + "output": { + "seatDisplay": { + "displayMessage": "Select your seats", + "seatMapVersion": "premium", + "totalAvailableSeats": 72 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "inputNode", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "cabinFillPercentage", + "value": "(cabin.occupiedSeats / cabin.totalSeats) * 100" + }, + { + "id": "expr2", + "key": "adjacentSeatsNeeded", + "value": "customer.groupSize > 1 ? customer.groupSize : 0" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "cabinFillCalculator", + "name": "calculateCabinFill", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "customerTier": "'platinum', 'gold'", + "fareClass": "'first', 'business'", + "cabinFill": "", + "adjacentSeats": "", + "showPreferred": "true", + "showStandard": "true", + "showRestricted": "true", + "unlockPremiumSeats": "true" + }, + { + "_id": "rule2", + "customerTier": "'platinum', 'gold'", + "fareClass": "'economy_plus', 'economy'", + "cabinFill": "< 70", + "adjacentSeats": "", + "showPreferred": "true", + "showStandard": "true", + "showRestricted": "false", + "unlockPremiumSeats": "true" + }, + { + "_id": "rule3", + "customerTier": "'silver'", + "fareClass": "'business'", + "cabinFill": "", + "adjacentSeats": "", + "showPreferred": "true", + "showStandard": "true", + "showRestricted": "false", + "unlockPremiumSeats": "true" + }, + { + "_id": "rule4", + "customerTier": "'silver'", + "fareClass": "'economy_plus', 'economy'", + "cabinFill": "< 60", + "adjacentSeats": "", + "showPreferred": "true", + "showStandard": "true", + "showRestricted": "false", + "unlockPremiumSeats": "false" + }, + { + "_id": "rule5", + "customerTier": "'silver'", + "fareClass": "'economy_plus', 'economy'", + "cabinFill": ">= 60", + "adjacentSeats": "", + "showPreferred": "false", + "showStandard": "true", + "showRestricted": "false", + "unlockPremiumSeats": "false" + }, + { + "_id": "rule6", + "customerTier": "'standard'", + "fareClass": "'business'", + "cabinFill": "", + "adjacentSeats": "", + "showPreferred": "false", + "showStandard": "true", + "showRestricted": "false", + "unlockPremiumSeats": "false" + }, + { + "_id": "rule7", + "customerTier": "'standard'", + "fareClass": "'economy_plus'", + "cabinFill": "< 50", + "adjacentSeats": "", + "showPreferred": "false", + "showStandard": "true", + "showRestricted": "false", + "unlockPremiumSeats": "false" + }, + { + "_id": "rule8", + "customerTier": "'standard'", + "fareClass": "'economy_plus'", + "cabinFill": ">= 50", + "adjacentSeats": "", + "showPreferred": "false", + "showStandard": "true", + "showRestricted": "false", + "unlockPremiumSeats": "false" + }, + { + "_id": "rule9", + "customerTier": "'standard'", + "fareClass": "'economy'", + "cabinFill": "", + "adjacentSeats": "", + "showPreferred": "false", + "showStandard": "true", + "showRestricted": "false", + "unlockPremiumSeats": "false" + }, + { + "_id": "rule10", + "customerTier": "", + "fareClass": "", + "cabinFill": "", + "adjacentSeats": "> 2", + "showPreferred": "false", + "showStandard": "true", + "showRestricted": "true", + "unlockPremiumSeats": "false" + }, + { + "_id": "rule11", + "customerTier": "", + "fareClass": "", + "cabinFill": "> 85", + "adjacentSeats": "", + "showPreferred": "false", + "showStandard": "true", + "showRestricted": "true", + "unlockPremiumSeats": "false" + }, + { + "_id": "rule12", + "customerTier": "", + "fareClass": "", + "cabinFill": "", + "adjacentSeats": "", + "showPreferred": "false", + "showStandard": "true", + "showRestricted": "false", + "unlockPremiumSeats": "false" + } + ], + "inputs": [ + { + "id": "customerTier", + "name": "Customer Tier", + "field": "customer.tier" + }, + { + "id": "fareClass", + "name": "Fare Class", + "field": "customer.fareClass" + }, + { + "id": "cabinFill", + "name": "Cabin Fill %", + "field": "cabinFillPercentage" + }, + { + "id": "adjacentSeats", + "name": "Adjacent Seats Needed", + "field": "adjacentSeatsNeeded" + } + ], + "outputs": [ + { + "id": "showPreferred", + "name": "Show Preferred Seats", + "field": "seatDisplay.showPreferredSeats" + }, + { + "id": "showStandard", + "name": "Show Standard Seats", + "field": "seatDisplay.showStandardSeats" + }, + { + "id": "showRestricted", + "name": "Show Restricted Seats", + "field": "seatDisplay.showRestrictedSeats" + }, + { + "id": "unlockPremiumSeats", + "name": "Unlock Premium Seats", + "field": "seatDisplay.unlockPremiumSeats" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "seatMapRules", + "name": "determineSeatAvailability", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr3", + "key": "seatDisplay.totalAvailableSeats", + "value": "cabin.totalSeats - cabin.occupiedSeats" + }, + { + "id": "expr4", + "key": "seatDisplay.seatMapVersion", + "value": "seatDisplay.unlockPremiumSeats ? 'premium' : 'standard'" + }, + { + "id": "expr5", + "key": "seatDisplay.displayMessage", + "value": "cabinFillPercentage > 80 ? 'Limited seats available' : 'Select your seats'" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "seatAvailabilityAdjuster", + "name": "adjustSeatAvailability", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "inputNode", + "targetId": "cabinFillCalculator", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "cabinFillCalculator", + "targetId": "seatMapRules", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "seatMapRules", + "targetId": "seatAvailabilityAdjuster", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/seller-approval-workflow.json b/test-data/graphs/seller-approval-workflow.json new file mode 100644 index 00000000..468dcaa0 --- /dev/null +++ b/test-data/graphs/seller-approval-workflow.json @@ -0,0 +1,383 @@ +{ + "tests": [ + { + "input": { + "businessCredentials": { + "hasValidDocumentation": true, + "yearsInBusiness": 2.5, + "businessName": "TechGadgets LLC", + "businessType": "Limited Liability Company", + "taxId": "12-3456789" + }, + "categoryExpertise": { + "primaryCategory": "Electronics", + "yearsOfExperience": 3, + "certifications": [ + "Consumer Electronics Specialist" + ], + "rating": 4 + }, + "inventoryQuality": { + "sampleProducts": 15, + "brandAuthenticity": true, + "productCompliance": true, + "productImageQuality": "high", + "rating": 4.2 + }, + "backgroundCheck": { + "passed": true, + "criminalRecord": false, + "creditScore": 720, + "identityVerified": true + } + }, + "output": { + "approvalDate": 1755622502, + "score": 85, + "status": "APPROVED" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "sellerApplicationRequest", + "position": { + "x": 110, + "y": 124.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i1-1": "false", + "i1-2": "", + "o1-1": "0", + "o1-2": "'invalid'", + "o1-3": "'Business documentation is missing or invalid'" + }, + { + "_id": "r2", + "i1-1": "true", + "i1-2": "< 1", + "o1-1": "15", + "o1-2": "'new'", + "o1-3": "'New business with limited history'" + }, + { + "_id": "r3", + "i1-1": "true", + "i1-2": "[1..3)", + "o1-1": "25", + "o1-2": "'established'", + "o1-3": "'Established business with moderate history'" + }, + { + "_id": "r4", + "i1-1": "true", + "i1-2": ">= 3", + "o1-1": "35", + "o1-2": "'mature'", + "o1-3": "'Mature business with solid history'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Has Valid Documentation", + "field": "businessCredentials.hasValidDocumentation" + }, + { + "id": "i1-2", + "name": "Years In Business", + "field": "businessCredentials.yearsInBusiness" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Credential Score", + "field": "evaluation.credentialScore" + }, + { + "id": "o1-2", + "name": "Business Status", + "field": "evaluation.businessStatus" + }, + { + "id": "o1-3", + "name": "Credential Notes", + "field": "evaluation.credentialNotes" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "businessCredentialsTable", + "name": "evaluateBusinessCredentials", + "position": { + "x": 430, + "y": 124.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1", + "i2-1": "== 'invalid'", + "i2-2": "", + "i2-3": "", + "i2-4": "", + "o2-1": "0", + "o2-2": "false", + "o2-3": "'Business credentials are invalid'" + }, + { + "_id": "r2", + "i2-1": "", + "i2-2": "< 3", + "i2-3": "", + "i2-4": "false", + "o2-1": "15", + "o2-2": "false", + "o2-3": "'Failed background check and low category expertise'" + }, + { + "_id": "r3", + "i2-1": "", + "i2-2": ">= 3", + "i2-3": "", + "i2-4": "false", + "o2-1": "30", + "o2-2": "false", + "o2-3": "'Failed background check despite good category expertise'" + }, + { + "_id": "r4", + "i2-1": "", + "i2-2": "", + "i2-3": "< 3", + "i2-4": "true", + "o2-1": "40", + "o2-2": "false", + "o2-3": "'Low inventory quality score'" + }, + { + "_id": "r5", + "i2-1": "", + "i2-2": ">= 3", + "i2-3": ">= 3", + "i2-4": "true", + "o2-1": "85", + "o2-2": "true", + "o2-3": "'Strong seller profile with good expertise and inventory'" + }, + { + "_id": "r6", + "i2-1": "", + "i2-2": ">= 4", + "i2-3": ">= 4", + "i2-4": "true", + "o2-1": "95", + "o2-2": "true", + "o2-3": "'Exceptional seller profile with excellent expertise and inventory'" + }, + { + "_id": "r7", + "i2-1": "", + "i2-2": "", + "i2-3": "", + "i2-4": "true", + "o2-1": "evaluation.credentialScore + 30", + "o2-2": "true", + "o2-3": "'Standard seller approval'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Business Status", + "field": "evaluation.businessStatus" + }, + { + "id": "i2-2", + "name": "Category Expertise", + "field": "categoryExpertise.rating" + }, + { + "id": "i2-3", + "name": "Inventory Quality", + "field": "inventoryQuality.rating" + }, + { + "id": "i2-4", + "name": "Background Check Passed", + "field": "backgroundCheck.passed" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Final Score", + "field": "evaluation.finalScore" + }, + { + "id": "o2-2", + "name": "Is Approved", + "field": "evaluation.isApproved" + }, + { + "id": "o2-3", + "name": "Evaluation Notes", + "field": "evaluation.notes" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "sellerEvaluationTable", + "name": "evaluateSellerQualifications", + "position": { + "x": 750, + "y": 124.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "approved", + "condition": "evaluation.isApproved == true", + "isDefault": false + }, + { + "id": "rejected", + "condition": "", + "isDefault": true + } + ] + }, + "id": "approvalSwitch", + "name": "routeApplication", + "position": { + "x": 1070, + "y": 124.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "status", + "value": "'APPROVED'" + }, + { + "id": "e2", + "key": "score", + "value": "evaluation.finalScore" + }, + { + "id": "e3", + "key": "approvalDate", + "value": "date('now')" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "approvalResult", + "name": "generateApprovalResult", + "position": { + "x": 1390, + "y": 75.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1", + "key": "status", + "value": "'REJECTED'" + }, + { + "id": "e2", + "key": "score", + "value": "evaluation.finalScore" + }, + { + "id": "e3", + "key": "rejectionDate", + "value": "date('now')" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "rejectionResult", + "name": "generateRejectionResult", + "position": { + "x": 1390, + "y": 173.5 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "businessCredentialsTable", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "businessCredentialsTable", + "targetId": "sellerEvaluationTable", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "sellerEvaluationTable", + "targetId": "approvalSwitch", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "approvalSwitch", + "targetId": "approvalResult", + "sourceHandle": "approved", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "approvalSwitch", + "targetId": "rejectionResult", + "sourceHandle": "rejected", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/seller-fee-calculator.json b/test-data/graphs/seller-fee-calculator.json new file mode 100644 index 00000000..75f63230 --- /dev/null +++ b/test-data/graphs/seller-fee-calculator.json @@ -0,0 +1,307 @@ +{ + "tests": [ + { + "input": { + "sellerData": { + "category": "premium", + "monthlySalesVolume": 72000, + "performanceRating": 4.9, + "inSpecialProgram": true + } + }, + "output": { + "effectiveFeeRate": 0.07, + "totalMonthlyFee": 5139.99, + "transactionFee": 5040 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "'premium'", + "i2": "> 100000", + "o1": "0.08", + "o2": "'premium'", + "o3": "99.99" + }, + { + "_id": "rule2", + "i1": "'premium'", + "i2": "> 50000", + "o1": "0.10", + "o2": "'premium'", + "o3": "99.99" + }, + { + "_id": "rule3", + "i1": "'premium'", + "i2": "", + "o1": "0.12", + "o2": "'premium'", + "o3": "99.99" + }, + { + "_id": "rule4", + "i1": "'standard'", + "i2": "> 75000", + "o1": "0.15", + "o2": "'standard'", + "o3": "29.99" + }, + { + "_id": "rule5", + "i1": "'standard'", + "i2": "> 25000", + "o1": "0.18", + "o2": "'standard'", + "o3": "29.99" + }, + { + "_id": "rule6", + "i1": "'standard'", + "i2": "", + "o1": "0.20", + "o2": "'standard'", + "o3": "29.99" + }, + { + "_id": "rule7", + "i1": "'basic'", + "i2": "> 25000", + "o1": "0.25", + "o2": "'basic'", + "o3": "0" + }, + { + "_id": "rule8", + "i1": "'basic'", + "i2": "", + "o1": "0.30", + "o2": "'basic'", + "o3": "0" + }, + { + "_id": "rule9", + "i1": "", + "i2": "", + "o1": "0.35", + "o2": "'basic'", + "o3": "0" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Seller Category", + "field": "sellerData.category" + }, + { + "id": "i2", + "name": "Monthly Sales Volume", + "field": "sellerData.monthlySalesVolume" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Base Fee Rate", + "field": "fees.baseFeeRate" + }, + { + "id": "o2", + "name": "Subscription Tier", + "field": "fees.subscriptionTier" + }, + { + "id": "o3", + "name": "Subscription Fee", + "field": "fees.subscriptionFee" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "sellerCategory", + "name": "determineCategoryFees", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "addRule1", + "i1": "> 4.8", + "i2": "true", + "o1": "-0.03", + "o2": "0", + "o3": "true" + }, + { + "_id": "addRule2", + "i1": "> 4.8", + "i2": "false", + "o1": "-0.02", + "o2": "0", + "o3": "false" + }, + { + "_id": "addRule3", + "i1": "> 4.5", + "i2": "true", + "o1": "-0.01", + "o2": "0", + "o3": "true" + }, + { + "_id": "addRule4", + "i1": "> 4.5", + "i2": "false", + "o1": "0", + "o2": "0", + "o3": "false" + }, + { + "_id": "addRule5", + "i1": "< 3.0", + "i2": "", + "o1": "0.05", + "o2": "25", + "o3": "false" + }, + { + "_id": "addRule6", + "i1": "< 4.0", + "i2": "", + "o1": "0.02", + "o2": "10", + "o3": "false" + }, + { + "_id": "addRule7", + "i1": "", + "i2": "", + "o1": "0", + "o2": "0", + "o3": "false" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Performance Rating", + "field": "sellerData.performanceRating" + }, + { + "id": "i2", + "name": "Special Program", + "field": "sellerData.inSpecialProgram" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Rate Adjustment", + "field": "fees.rateAdjustment" + }, + { + "id": "o2", + "name": "Additional Service Charge", + "field": "fees.additionalServiceCharge" + }, + { + "id": "o3", + "name": "Promotional Benefits", + "field": "fees.hasPromotionalBenefits" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "additionalFees", + "name": "calculateAdditionalFees", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "effectiveFeeRate", + "value": "fees.baseFeeRate + fees.rateAdjustment" + }, + { + "id": "expr2", + "key": "transactionFee", + "value": "sellerData.monthlySalesVolume * $.effectiveFeeRate" + }, + { + "id": "expr3", + "key": "totalMonthlyFee", + "value": "$.transactionFee + fees.subscriptionFee + fees.additionalServiceCharge" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "calculateTotal", + "name": "calculateTotalFees", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "sellerCategory", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "sellerCategory", + "targetId": "additionalFees", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "additionalFees", + "targetId": "calculateTotal", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/service-level-agreement-enforcement.json b/test-data/graphs/service-level-agreement-enforcement.json new file mode 100644 index 00000000..e701ef22 --- /dev/null +++ b/test-data/graphs/service-level-agreement-enforcement.json @@ -0,0 +1,575 @@ +{ + "tests": [ + { + "input": { + "service": { + "id": "internet_service_123", + "name": "Business Fiber Internet", + "status": "down", + "downtimeDuration": 45, + "responseTime": 320, + "packetLoss": 0.8, + "startTime": "2025-03-19T15:30:00Z" + }, + "customer": { + "id": "cust_789", + "name": "Acme Corporation", + "serviceTier": "premium", + "contractId": "contract_456", + "contactEmail": "support@acmecorp.com" + }, + "incident": { + "id": "inc_123456", + "reportedTime": "2025-03-19T15:45:00Z", + "reportedBy": "automated_monitoring" + } + }, + "output": { + "breachDescription": "Excessive downtime for premium customer", + "compensationAmount": 225, + "compensationType": "service_credit", + "customer": { + "contactEmail": "support@acmecorp.com", + "contractId": "contract_456", + "id": "cust_789", + "name": "Acme Corporation", + "serviceTier": "premium" + }, + "customerTier": "premium", + "downtimeDuration": 45, + "escalationLevel": "senior_management", + "escalationTimeframe": "immediate", + "incident": { + "id": "inc_123456", + "reportedBy": "automated_monitoring", + "reportedTime": "2025-03-19T15:45:00Z" + }, + "isDowntime": true, + "packetLoss": 0.8, + "parameterType": "downtime", + "parameterValue": 45, + "requiresEscalation": true, + "responseTime": 320, + "service": { + "downtimeDuration": 45, + "id": "internet_service_123", + "name": "Business Fiber Internet", + "packetLoss": 0.8, + "responseTime": 320, + "startTime": "2025-03-19T15:30:00Z", + "status": "down" + }, + "severityLevel": "critical", + "severityScore": 3, + "slaBreached": true + } + } + ], + "nodes": [ + { + "id": "input1", + "name": "request", + "type": "inputNode", + "content": { + "schema": "" + }, + "position": { + "x": 110, + "y": 114 + } + }, + { + "id": "validateSLA", + "name": "validateServiceParameters", + "type": "expressionNode", + "content": { + "inputField": null, + "outputPath": null, + "expressions": [ + { + "id": "expr1", + "key": "isDowntime", + "value": "service.status == 'down'" + }, + { + "id": "expr2", + "key": "downtimeDuration", + "value": "service.downtimeDuration ?? 0" + }, + { + "id": "expr3", + "key": "responseTime", + "value": "service.responseTime ?? 0" + }, + { + "id": "expr4", + "key": "packetLoss", + "value": "service.packetLoss ?? 0" + }, + { + "id": "expr5", + "key": "customerTier", + "value": "customer.serviceTier ?? 'standard'" + } + ], + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 430, + "y": 114 + } + }, + { + "id": "determineParameterType", + "name": "determineParameterType", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "i1": "isDowntime == true", + "o1": "'downtime'", + "o2": "downtimeDuration", + "_id": "param1" + }, + { + "i1": "responseTime > 0", + "o1": "'responseTime'", + "o2": "responseTime", + "_id": "param2" + }, + { + "i1": "packetLoss > 0", + "o1": "'packetLoss'", + "o2": "packetLoss", + "_id": "param3" + }, + { + "i1": "", + "o1": "'unknown'", + "o2": "0", + "_id": "param4" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Input" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Parameter Type", + "field": "parameterType" + }, + { + "id": "o2", + "name": "Parameter Value", + "field": "parameterValue" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 750, + "y": 114 + } + }, + { + "id": "assessSLABreach", + "name": "assessSLABreach", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "o1": "true", + "o2": "'Excessive downtime for premium customer'", + "_id": "rule1", + "paramType": "'downtime'", + "paramValue": "> 10", + "serviceLevel": "'premium'" + }, + { + "o1": "true", + "o2": "'Excessive downtime for standard customer'", + "_id": "rule2", + "paramType": "'downtime'", + "paramValue": "> 30", + "serviceLevel": "'standard'" + }, + { + "o1": "true", + "o2": "'Response time exceeds premium SLA'", + "_id": "rule3", + "paramType": "'responseTime'", + "paramValue": "> 200", + "serviceLevel": "'premium'" + }, + { + "o1": "true", + "o2": "'Response time exceeds standard SLA'", + "_id": "rule4", + "paramType": "'responseTime'", + "paramValue": "> 500", + "serviceLevel": "'standard'" + }, + { + "o1": "true", + "o2": "'Packet loss exceeds premium SLA'", + "_id": "rule5", + "paramType": "'packetLoss'", + "paramValue": "> 0.5", + "serviceLevel": "'premium'" + }, + { + "o1": "true", + "o2": "'Packet loss exceeds standard SLA'", + "_id": "rule6", + "paramType": "'packetLoss'", + "paramValue": "> 2", + "serviceLevel": "'standard'" + }, + { + "o1": "false", + "o2": "'No SLA breach detected'", + "_id": "rule7", + "paramType": "", + "paramValue": "", + "serviceLevel": "" + } + ], + "inputs": [ + { + "id": "paramType", + "name": "Parameter Type", + "field": "parameterType" + }, + { + "id": "serviceLevel", + "name": "Service Level", + "field": "customerTier" + }, + { + "id": "paramValue", + "name": "Parameter Value", + "field": "parameterValue" + } + ], + "outputs": [ + { + "id": "o1", + "name": "SLA Breached", + "field": "slaBreached" + }, + { + "id": "o2", + "name": "Breach Description", + "field": "breachDescription" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 1070, + "y": 114 + } + }, + { + "id": "determineSeverity", + "name": "determineSeverity", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "o1": "'critical'", + "o2": "3", + "_id": "severity1", + "_description": "", + "10022132-3b17-452f-9e87-cc67dcbc1682": "true", + "3b99eee0-25eb-49b6-8cf0-6daa7fcbfdc3": "'downtime'", + "d3d1e8b0-5f9f-4867-a326-8cfdbccdbb94": "'premium'" + }, + { + "o1": "'high'", + "o2": "2", + "_id": "severity2", + "_description": "", + "10022132-3b17-452f-9e87-cc67dcbc1682": "true", + "3b99eee0-25eb-49b6-8cf0-6daa7fcbfdc3": "'downtime'", + "d3d1e8b0-5f9f-4867-a326-8cfdbccdbb94": "'standard'" + }, + { + "o1": "'high'", + "o2": "2", + "_id": "severity3", + "_description": "", + "10022132-3b17-452f-9e87-cc67dcbc1682": "true", + "3b99eee0-25eb-49b6-8cf0-6daa7fcbfdc3": "'responseTime'", + "d3d1e8b0-5f9f-4867-a326-8cfdbccdbb94": "'premium'" + }, + { + "o1": "'medium'", + "o2": "1", + "_id": "severity4", + "_description": "", + "10022132-3b17-452f-9e87-cc67dcbc1682": "true", + "3b99eee0-25eb-49b6-8cf0-6daa7fcbfdc3": "'responseTime'", + "d3d1e8b0-5f9f-4867-a326-8cfdbccdbb94": "'standard'" + }, + { + "o1": "'high'", + "o2": "2", + "_id": "severity5", + "_description": "", + "10022132-3b17-452f-9e87-cc67dcbc1682": "true", + "3b99eee0-25eb-49b6-8cf0-6daa7fcbfdc3": "'packetLoss'", + "d3d1e8b0-5f9f-4867-a326-8cfdbccdbb94": "'premium'" + }, + { + "o1": "'medium'", + "o2": "1", + "_id": "severity6", + "_description": "", + "10022132-3b17-452f-9e87-cc67dcbc1682": "true", + "3b99eee0-25eb-49b6-8cf0-6daa7fcbfdc3": "'packetLoss'", + "d3d1e8b0-5f9f-4867-a326-8cfdbccdbb94": "'standard'" + }, + { + "o1": "'none'", + "o2": "0", + "_id": "severity7", + "_description": "", + "10022132-3b17-452f-9e87-cc67dcbc1682": "", + "3b99eee0-25eb-49b6-8cf0-6daa7fcbfdc3": "", + "d3d1e8b0-5f9f-4867-a326-8cfdbccdbb94": "" + } + ], + "inputs": [ + { + "id": "10022132-3b17-452f-9e87-cc67dcbc1682", + "name": "SLA Breached", + "field": "slaBreached" + }, + { + "id": "3b99eee0-25eb-49b6-8cf0-6daa7fcbfdc3", + "name": "Parameter Type", + "field": "parameterType" + }, + { + "id": "d3d1e8b0-5f9f-4867-a326-8cfdbccdbb94", + "name": "Customer tier", + "field": "customerTier" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Severity Level", + "field": "severityLevel" + }, + { + "id": "o2", + "name": "Severity Score", + "field": "severityScore" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 1390, + "y": 114 + } + }, + { + "id": "determineEscalation", + "name": "determineEscalation", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "i1": "'critical'", + "o1": "true", + "o2": "'immediate'", + "o3": "'senior_management'", + "_id": "escalation1", + "_description": "" + }, + { + "i1": "'high'", + "o1": "true", + "o2": "'4_hours'", + "o3": "'service_manager'", + "_id": "escalation2", + "_description": "" + }, + { + "i1": "'medium'", + "o1": "true", + "o2": "'24_hours'", + "o3": "'support_team'", + "_id": "escalation3", + "_description": "" + }, + { + "i1": "", + "o1": "false", + "o2": "'none'", + "o3": "'none'", + "_id": "escalation4", + "_description": "" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Severity level", + "field": "severityLevel" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Requires Escalation", + "field": "requiresEscalation" + }, + { + "id": "o2", + "name": "Escalation Timeframe", + "field": "escalationTimeframe" + }, + { + "id": "o3", + "name": "Escalation Level", + "field": "escalationLevel" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 2030, + "y": 114 + } + }, + { + "id": "ed8355c4-aea1-4526-82b3-56d7d98efa92", + "name": "calculateCompensation", + "type": "decisionTableNode", + "content": { + "rules": [ + { + "_id": "32a4f6a9-6631-4a5b-9fad-75c5f22bb591", + "_description": "", + "bd7b183b-2e9f-4fec-bc0f-e915864bd5eb": "true", + "c3716324-94d0-4a9a-a3f1-4d6041b0a9aa": "'service_credit'", + "d83f698c-a398-49b4-9bca-622081180bac": "parameterValue * 5", + "f74a521d-8f22-47ba-b800-1c7a8e69d606": "'premium'" + }, + { + "_id": "90cf3b42-e758-4dff-8f41-4e5ec409fdec", + "_description": "", + "bd7b183b-2e9f-4fec-bc0f-e915864bd5eb": "true", + "c3716324-94d0-4a9a-a3f1-4d6041b0a9aa": "'account_credit'", + "d83f698c-a398-49b4-9bca-622081180bac": "parameterValue * 2", + "f74a521d-8f22-47ba-b800-1c7a8e69d606": "" + }, + { + "_id": "5e7f3275-c1ea-4969-a071-c4453a85fbbf", + "_description": "", + "bd7b183b-2e9f-4fec-bc0f-e915864bd5eb": "", + "c3716324-94d0-4a9a-a3f1-4d6041b0a9aa": "'none'", + "d83f698c-a398-49b4-9bca-622081180bac": "0", + "f74a521d-8f22-47ba-b800-1c7a8e69d606": "" + } + ], + "inputs": [ + { + "id": "bd7b183b-2e9f-4fec-bc0f-e915864bd5eb", + "name": "SLA Breached", + "field": "slaBreached" + }, + { + "id": "f74a521d-8f22-47ba-b800-1c7a8e69d606", + "name": "Customer tier", + "field": "customerTier" + } + ], + "outputs": [ + { + "id": "d83f698c-a398-49b4-9bca-622081180bac", + "name": "Compensation amount", + "field": "compensationAmount" + }, + { + "id": "c3716324-94d0-4a9a-a3f1-4d6041b0a9aa", + "name": "Compensation type", + "field": "compensationType" + } + ], + "hitPolicy": "first", + "inputField": null, + "outputPath": null, + "passThrough": true, + "executionMode": "single" + }, + "position": { + "x": 1710, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "type": "edge", + "sourceId": "input1", + "targetId": "validateSLA" + }, + { + "id": "edge2", + "type": "edge", + "sourceId": "validateSLA", + "targetId": "determineParameterType" + }, + { + "id": "edge3", + "type": "edge", + "sourceId": "determineParameterType", + "targetId": "assessSLABreach" + }, + { + "id": "edge4", + "type": "edge", + "sourceId": "assessSLABreach", + "targetId": "determineSeverity" + }, + { + "id": "f7976e4a-7d56-437e-aaa3-4ccbedc164d4", + "type": "edge", + "sourceId": "determineSeverity", + "targetId": "ed8355c4-aea1-4526-82b3-56d7d98efa92" + }, + { + "id": "efe1c0df-71b0-4e9d-9544-5010b3c5bb84", + "type": "edge", + "sourceId": "ed8355c4-aea1-4526-82b3-56d7d98efa92", + "targetId": "determineEscalation" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/shipping-carrier-selector.json b/test-data/graphs/shipping-carrier-selector.json new file mode 100644 index 00000000..e458cce7 --- /dev/null +++ b/test-data/graphs/shipping-carrier-selector.json @@ -0,0 +1,379 @@ +{ + "tests": [ + { + "input": { + "length": 45, + "width": 35, + "height": 25, + "weight": 12.5, + "destination": "domestic", + "deliveryTimeline": "express", + "priorityFactor": "cost" + }, + "output": { + "baseCosts": { + "EcoShip": 21.75, + "FastTrack": 40.5, + "GlobalExpress": 87.5, + "GlobalStandard": 60, + "HeavyHauler": 65, + "QuickShip": 39.75, + "RegularPost": 25, + "SpeedyExpress": 56.25, + "StandardCourier": 28.25, + "WorldWide": 77.5 + }, + "carrierCosts": [ + { + "carrier": "FastTrack", + "cost": 40.5 + }, + { + "carrier": "QuickShip", + "cost": 39.75 + } + ], + "chargableWeight": 12.5, + "deliveryTimeline": "express", + "destination": "domestic", + "eligibleCarriers": [ + "FastTrack", + "QuickShip" + ], + "height": 25, + "isOversized": false, + "length": 45, + "priorityFactor": "cost", + "serviceLevel": "express", + "validation": { + "isValid": true + }, + "volumetricWeight": 7.875, + "weight": 12.5, + "width": 35 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 115.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "weight <= 0 or length <= 0 or width <= 0 or height <= 0", + "o1": "'Package dimensions and weight must be positive values'", + "o2": "false" + }, + { + "_id": "rule2", + "i1": "weight > 70", + "o1": "'Package exceeds maximum weight limit of 70kg'", + "o2": "false" + }, + { + "_id": "rule3", + "i1": "length > 200 or width > 200 or height > 200", + "o1": "'Package exceeds maximum dimension limit of 200cm'", + "o2": "false" + }, + { + "_id": "rule4", + "i1": "deliveryTimeline != 'standard' and deliveryTimeline != 'express' and deliveryTimeline != 'same-day'", + "o1": "'Invalid delivery timeline option'", + "o2": "false" + }, + { + "_id": "rule5", + "i1": "", + "o1": "", + "o2": "true" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Input" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Error", + "field": "validation.error" + }, + { + "id": "o2", + "name": "IsValid", + "field": "validation.isValid" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "validate", + "name": "validatePackage", + "position": { + "x": 430, + "y": 115.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "validation.isValid == false", + "o1": "'none'" + }, + { + "_id": "rule2", + "i1": "deliveryTimeline == 'same-day'", + "o1": "'premium'" + }, + { + "_id": "rule3", + "i1": "deliveryTimeline == 'express'", + "o1": "'express'" + }, + { + "_id": "rule4", + "i1": "deliveryTimeline == 'standard'", + "o1": "'standard'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Input" + } + ], + "outputs": [ + { + "id": "o1", + "name": "ServiceLevel", + "field": "serviceLevel" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "serviceLevel", + "name": "determineServiceLevel", + "position": { + "x": 1070, + "y": 66.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "rule1", + "i1": "validation.isValid == false", + "o1": "[]" + }, + { + "_id": "rule2", + "i1": "serviceLevel == 'premium' and destination == 'domestic' and weight <= 15", + "o1": "['SpeedyExpress']" + }, + { + "_id": "rule3", + "i1": "serviceLevel == 'express' and destination == 'domestic' and weight <= 30", + "o1": "['FastTrack', 'QuickShip']" + }, + { + "_id": "rule4", + "i1": "serviceLevel == 'express' and destination == 'international' and weight <= 20", + "o1": "['GlobalExpress', 'WorldWide']" + }, + { + "_id": "rule5", + "i1": "serviceLevel == 'standard' and destination == 'domestic' and weight <= 50", + "o1": "['RegularPost', 'EcoShip', 'StandardCourier']" + }, + { + "_id": "rule6", + "i1": "serviceLevel == 'standard' and destination == 'international' and weight <= 30", + "o1": "['GlobalStandard', 'WorldWide']" + }, + { + "_id": "rule7", + "i1": "weight > 50 and weight <= 70", + "o1": "['HeavyHauler']" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Input" + } + ], + "outputs": [ + { + "id": "o1", + "name": "EligibleCarriers", + "field": "carriers" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "eligibleCarriers", + "executionMode": "single", + "passThorough": false + }, + "id": "carrierEligibility", + "name": "determineEligibleCarriers", + "position": { + "x": 1390, + "y": 66.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "bd88f97d-d7fa-4342-b880-e611ba6ee610", + "key": "eligibleCarriers", + "value": "flatten(map(eligibleCarriers, #.carriers))" + }, + { + "id": "expr1", + "key": "volumetricWeight", + "value": "(length * width * height) / 5000" + }, + { + "id": "expr2", + "key": "chargableWeight", + "value": "max([weight, $.volumetricWeight])" + }, + { + "id": "expr3", + "key": "isOversized", + "value": "length > 100 or width > 100 or height > 100" + }, + { + "id": "expr4", + "key": "baseCosts", + "value": "{\n \"SpeedyExpress\": 25 + ($.chargableWeight * 2.5) + ($.isOversized ? 15 : 0),\n \"FastTrack\": 18 + ($.chargableWeight * 1.8) + ($.isOversized ? 12 : 0),\n \"QuickShip\": 16 + ($.chargableWeight * 1.9) + ($.isOversized ? 10 : 0),\n \"GlobalExpress\": 35 + ($.chargableWeight * 4.2) + ($.isOversized ? 25 : 0),\n \"WorldWide\": 30 + ($.chargableWeight * 3.8) + ($.isOversized ? 20 : 0),\n \"RegularPost\": 10 + ($.chargableWeight * 1.2) + ($.isOversized ? 8 : 0),\n \"EcoShip\": 8 + ($.chargableWeight * 1.1) + ($.isOversized ? 7 : 0),\n \"StandardCourier\": 12 + ($.chargableWeight * 1.3) + ($.isOversized ? 9 : 0),\n \"GlobalStandard\": 25 + ($.chargableWeight * 2.8) + ($.isOversized ? 15 : 0),\n \"HeavyHauler\": 40 + ($.chargableWeight * 2.0) + ($.isOversized ? 30 : 0)\n}" + }, + { + "id": "expr5", + "key": "carrierCosts", + "value": "filter(\n map($.eligibleCarriers, {\n 'carrier': #,\n 'cost': $.baseCosts[#]\n }),\n #.cost < 999999\n)" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "costCalculation", + "name": "calculateCosts", + "position": { + "x": 1710, + "y": 66.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "de01933e-42a2-4995-8f84-9b9ab0a3d1ec", + "condition": "validation.isValid", + "isDefault": false + }, + { + "id": "e9a52c8a-8553-4abb-b232-3a5283066ce8", + "condition": "", + "isDefault": true + } + ] + }, + "id": "1842fd5e-dc7e-480e-b501-07f93500a14c", + "name": "switch1", + "position": { + "x": 750, + "y": 115.5 + } + }, + { + "type": "outputNode", + "content": { + "schema": "" + }, + "id": "0e7b0128-a7bc-404d-894a-423fd79f7ea9", + "name": "response", + "position": { + "x": 1070, + "y": 164.5 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "validate", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "serviceLevel", + "targetId": "carrierEligibility", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "carrierEligibility", + "targetId": "costCalculation", + "type": "edge" + }, + { + "id": "099c6707-868d-42c1-8953-92397134ccfb", + "sourceId": "validate", + "type": "edge", + "targetId": "1842fd5e-dc7e-480e-b501-07f93500a14c" + }, + { + "id": "9b03863d-954d-43bf-8a1e-a3a091457647", + "sourceId": "1842fd5e-dc7e-480e-b501-07f93500a14c", + "type": "edge", + "targetId": "serviceLevel", + "sourceHandle": "de01933e-42a2-4995-8f84-9b9ab0a3d1ec" + }, + { + "id": "e693e75d-93f9-4d03-94c6-7cc798063645", + "sourceId": "1842fd5e-dc7e-480e-b501-07f93500a14c", + "type": "edge", + "targetId": "0e7b0128-a7bc-404d-894a-423fd79f7ea9", + "sourceHandle": "e9a52c8a-8553-4abb-b232-3a5283066ce8" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/smart-financial-product-matcher.json b/test-data/graphs/smart-financial-product-matcher.json new file mode 100644 index 00000000..f4145743 --- /dev/null +++ b/test-data/graphs/smart-financial-product-matcher.json @@ -0,0 +1,249 @@ +{ + "tests": [ + { + "input": { + "customerProfile": { + "customerId": "C12345", + "name": "Jane Smith", + "age": 35, + "creditScore": 720, + "annualIncome": 85000, + "employmentStatus": "employed", + "existingProducts": [ + "checking_account" + ], + "financialGoals": [ + "home_purchase", + "retirement_savings" + ], + "riskTolerance": "moderate" + } + }, + "output": { + "recommendationMessage": "Start rebuilding your credit with these financial tools.", + "recommendedProducts": [ + "secured_credit_card", + "basic_checking", + "credit_builder_loan" + ] + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "customerProfile", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1-1": ">= 750", + "o1-1": "'excellent'" + }, + { + "_id": "rule2", + "i1-1": ">= 700", + "o1-1": "'good'" + }, + { + "_id": "rule3", + "i1-1": ">= 650", + "o1-1": "'fair'" + }, + { + "_id": "rule4", + "i1-1": "", + "o1-1": "'poor'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Credit Score", + "field": "creditScore" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Credit Category", + "field": "creditCategory" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "creditScoreEvaluation", + "name": "evaluateCreditScore", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i2-1": ">= 120000", + "o2-1": "'high'" + }, + { + "_id": "rule2", + "i2-1": ">= 60000", + "o2-1": "'medium'" + }, + { + "_id": "rule3", + "i2-1": "", + "o2-1": "'low'" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Annual Income", + "field": "annualIncome" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Income Category", + "field": "incomeCategory" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "incomeEvaluation", + "name": "evaluateIncome", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i3-1": "'excellent'", + "i3-2": "'high'", + "o3-1": "['premium_credit_card', 'investment_account', 'high_yield_savings', 'wealth_management']", + "o3-2": "'You qualify for our premium services with competitive rates and exclusive benefits.'" + }, + { + "_id": "rule2", + "i3-1": "'excellent'", + "i3-2": "'medium'", + "o3-1": "['rewards_credit_card', 'investment_account', 'high_yield_savings']", + "o3-2": "'You qualify for our premium credit products and investment services.'" + }, + { + "_id": "rule3", + "i3-1": "'good'", + "i3-2": "'high', 'medium'", + "o3-1": "['rewards_credit_card', 'personal_loan', 'investment_account']", + "o3-2": "'Based on your good credit and income, we recommend these financial products.'" + }, + { + "_id": "rule4", + "i3-1": "'fair'", + "i3-2": "'high', 'medium'", + "o3-1": "['secured_credit_card', 'savings_account', 'credit_builder_loan']", + "o3-2": "'These products can help you build credit while meeting your financial needs.'" + }, + { + "_id": "rule5", + "i3-1": "'poor'", + "i3-2": "", + "o3-1": "['secured_credit_card', 'basic_checking', 'credit_builder_loan']", + "o3-2": "'Start rebuilding your credit with these financial tools.'" + }, + { + "_id": "rule6", + "i3-1": "", + "i3-2": "'low'", + "o3-1": "['basic_checking', 'savings_account', 'secured_credit_card']", + "o3-2": "'These accounts have minimal fees and are designed to help you manage your finances.'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Credit Category", + "field": "creditCategory" + }, + { + "id": "i3-2", + "name": "Income Category", + "field": "incomeCategory" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Recommended Products", + "field": "recommendedProducts" + }, + { + "id": "o3-2", + "name": "Recommendation Message", + "field": "recommendationMessage" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "productRecommendation", + "name": "recommendProducts", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "creditScoreEvaluation", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "creditScoreEvaluation", + "targetId": "incomeEvaluation", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "incomeEvaluation", + "targetId": "productRecommendation", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/supply-chain-risk.json b/test-data/graphs/supply-chain-risk.json new file mode 100644 index 00000000..6de85e4c --- /dev/null +++ b/test-data/graphs/supply-chain-risk.json @@ -0,0 +1,316 @@ +{ + "tests": [ + { + "input": { + "supplier": { + "name": "GlobalTech Supplies Inc.", + "location": "medium_risk_region", + "performanceScore": 82, + "alternateSourcesCount": 2, + "products": [ + { + "id": "P123", + "name": "Semiconductor Chip", + "criticalComponent": true + } + ], + "relationshipDurationMonths": 36 + }, + "geopoliticalTensions": true, + "marketVolatility": "medium", + "supplyCategory": "electronics", + "leadTimeData": { + "averageDays": 45, + "historicalVariance": 8 + } + }, + "output": { + "adjustedRiskScore": 57, + "assessment": { + "baseRiskCategory": "medium", + "baseRiskScore": 40, + "recommendedAction": "Monitor supplier performance and conduct quarterly reviews" + }, + "finalAssessment": { + "leadTimeImpact": "minor", + "priorityLevel": "medium", + "riskCategory": "medium" + }, + "geopoliticalFactor": 1.3, + "geopoliticalTensions": true, + "leadTimeData": { + "averageDays": 45, + "historicalVariance": 8 + }, + "marketVolatility": "medium", + "marketVolatilityFactor": 1.1, + "supplier": { + "alternateSourcesCount": 2, + "location": "medium_risk_region", + "name": "GlobalTech Supplies Inc.", + "performanceScore": 82, + "products": [ + { + "criticalComponent": true, + "id": "P123", + "name": "Semiconductor Chip" + } + ], + "relationshipDurationMonths": 36 + }, + "supplyCategory": "electronics" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "supplierLocation": "'high_risk_region'", + "historicalPerformance": "< 70", + "alternativeSources": "< 2", + "riskScore": "80", + "riskCategory": "'critical'", + "mitigation": "'Immediate action required: Identify alternative suppliers'" + }, + { + "_id": "rule2", + "supplierLocation": "'high_risk_region'", + "historicalPerformance": ">= 70", + "alternativeSources": "", + "riskScore": "65", + "riskCategory": "'high'", + "mitigation": "'Develop backup suppliers and increase safety stock'" + }, + { + "_id": "rule3", + "supplierLocation": "'medium_risk_region'", + "historicalPerformance": "< 80", + "alternativeSources": "< 3", + "riskScore": "60", + "riskCategory": "'high'", + "mitigation": "'Implement dual-sourcing strategy'" + }, + { + "_id": "rule4", + "supplierLocation": "'medium_risk_region'", + "historicalPerformance": ">= 80", + "alternativeSources": "", + "riskScore": "40", + "riskCategory": "'medium'", + "mitigation": "'Monitor supplier performance and conduct quarterly reviews'" + }, + { + "_id": "rule5", + "supplierLocation": "'low_risk_region'", + "historicalPerformance": "< 75", + "alternativeSources": "", + "riskScore": "35", + "riskCategory": "'medium'", + "mitigation": "'Schedule regular performance reviews'" + }, + { + "_id": "rule6", + "supplierLocation": "'low_risk_region'", + "historicalPerformance": ">= 75", + "alternativeSources": ">= 3", + "riskScore": "15", + "riskCategory": "'low'", + "mitigation": "'Standard monitoring procedures'" + }, + { + "_id": "rule7", + "supplierLocation": "", + "historicalPerformance": "", + "alternativeSources": "", + "riskScore": "50", + "riskCategory": "'medium'", + "mitigation": "'Conduct detailed supplier assessment'" + } + ], + "inputs": [ + { + "id": "supplierLocation", + "name": "Supplier Location", + "field": "supplier.location" + }, + { + "id": "historicalPerformance", + "name": "Historical Performance Score", + "field": "supplier.performanceScore" + }, + { + "id": "alternativeSources", + "name": "Alternative Sources Count", + "field": "supplier.alternateSourcesCount" + } + ], + "outputs": [ + { + "id": "riskScore", + "name": "Risk Score", + "field": "assessment.baseRiskScore" + }, + { + "id": "riskCategory", + "name": "Risk Category", + "field": "assessment.baseRiskCategory" + }, + { + "id": "mitigation", + "name": "Recommended Mitigation", + "field": "assessment.recommendedAction" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "supplierRiskEvaluation", + "name": "supplierRiskEvaluation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "geopoliticalFactor", + "value": "geopoliticalTensions == true ? 1.3 : 1.0" + }, + { + "id": "expr2", + "key": "marketVolatilityFactor", + "value": "marketVolatility == 'high' ? 1.2 : (marketVolatility == 'medium' ? 1.1 : 1.0)" + }, + { + "id": "expr3", + "key": "adjustedRiskScore", + "value": "min([round(assessment.baseRiskScore * $.geopoliticalFactor * $.marketVolatilityFactor), 100])" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "geopoliticalRiskCalculation", + "name": "geopoliticalRiskCalculation", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "finalRule1", + "adjustedRiskScore": ">= 75", + "finalCategory": "'critical'", + "leadTimeImpact": "'significant'", + "priorityLevel": "'immediate'" + }, + { + "_id": "finalRule2", + "adjustedRiskScore": ">= 60", + "finalCategory": "'high'", + "leadTimeImpact": "'moderate'", + "priorityLevel": "'high'" + }, + { + "_id": "finalRule3", + "adjustedRiskScore": ">= 40", + "finalCategory": "'medium'", + "leadTimeImpact": "'minor'", + "priorityLevel": "'medium'" + }, + { + "_id": "finalRule4", + "adjustedRiskScore": "", + "finalCategory": "'low'", + "leadTimeImpact": "'minimal'", + "priorityLevel": "'routine'" + } + ], + "inputs": [ + { + "id": "adjustedRiskScore", + "name": "Adjusted Risk Score", + "field": "adjustedRiskScore" + } + ], + "outputs": [ + { + "id": "finalCategory", + "name": "Final Risk Category", + "field": "finalAssessment.riskCategory" + }, + { + "id": "leadTimeImpact", + "name": "Lead Time Impact", + "field": "finalAssessment.leadTimeImpact" + }, + { + "id": "priorityLevel", + "name": "Priority Level", + "field": "finalAssessment.priorityLevel" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "overallRiskAssessment", + "name": "overallRiskAssessment", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "supplierRiskEvaluation", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "supplierRiskEvaluation", + "targetId": "geopoliticalRiskCalculation", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "geopoliticalRiskCalculation", + "targetId": "overallRiskAssessment", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/tax-exemption.json b/test-data/graphs/tax-exemption.json new file mode 100644 index 00000000..aa770775 --- /dev/null +++ b/test-data/graphs/tax-exemption.json @@ -0,0 +1,295 @@ +{ + "tests": [ + { + "input": { + "organizationType": "nonprofit", + "annualRevenue": 175000, + "publicSupportPercentage": 45.7, + "politicalActivity": false, + "charitableActivitiesPercentage": 92.3 + }, + "output": { + "annualRevenue": 175000, + "charitableActivitiesPercentage": 92.3, + "organizationType": "nonprofit", + "politicalActivity": false, + "publicSupportPercentage": 45.7, + "result": { + "annualFilingRequirement": "990-EZ", + "classification": "501(c)(3)", + "effectiveDate": "2025-03-20", + "explanation": "Public charity with substantial public support", + "publicDisclosureRequired": true, + "status": "Exempt" + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"organizationType\": {\n \"type\": \"string\",\n \"description\": \"Type of organization (e.g., nonprofit, religious, educational)\"\n },\n \"annualRevenue\": {\n \"type\": \"number\",\n \"description\": \"Annual revenue in USD\"\n },\n \"publicSupportPercentage\": {\n \"type\": \"number\",\n \"description\": \"Percentage of funding from public sources\"\n },\n \"politicalActivity\": {\n \"type\": \"boolean\",\n \"description\": \"Whether the organization engages in political activities\"\n },\n \"charitableActivitiesPercentage\": {\n \"type\": \"number\",\n \"description\": \"Percentage of activities that are charitable in nature\"\n }\n }\n}" + }, + "id": "ip1", + "name": "organizationRequest", + "position": { + "x": 110, + "y": 124.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "_description": "501(c)(3) Religious Organization", + "i1-1": "'religious'", + "i1-2": "false", + "i1-3": ">= 85", + "o1-1": "'501(c)(3)'", + "o1-2": "'Exempt'", + "o1-3": "'Religious organization with no political activity and high charitable focus'" + }, + { + "_id": "r1-2", + "_description": "501(c)(3) Educational Organization", + "i1-1": "'educational'", + "i1-2": "false", + "i1-3": ">= 85", + "o1-1": "'501(c)(3)'", + "o1-2": "'Exempt'", + "o1-3": "'Educational institution with no political activity and high charitable focus'" + }, + { + "_id": "r1-3", + "_description": "501(c)(3) Nonprofit with high public support", + "i1-1": "'nonprofit'", + "i1-2": "false", + "i1-3": ">= 85", + "i1-4": ">= 33.3", + "o1-1": "'501(c)(3)'", + "o1-2": "'Exempt'", + "o1-3": "'Public charity with substantial public support'" + }, + { + "_id": "r1-4", + "_description": "501(c)(3) Nonprofit with moderate public support", + "i1-1": "'nonprofit'", + "i1-2": "false", + "i1-3": ">= 85", + "i1-4": ">= 10 and < 33.3", + "o1-1": "'501(c)(3)'", + "o1-2": "'Exempt'", + "o1-3": "'Public charity with moderate public support'" + }, + { + "_id": "r1-5", + "_description": "501(c)(3) Private Foundation", + "i1-1": "'nonprofit'", + "i1-2": "false", + "i1-3": ">= 85", + "i1-4": "< 10", + "o1-1": "'501(c)(3)'", + "o1-2": "'Exempt - Private Foundation'", + "o1-3": "'Private foundation with limited public support'" + }, + { + "_id": "r1-6", + "_description": "Political Activity Disqualification", + "i1-2": "true", + "o1-1": "'Non-exempt'", + "o1-2": "'Not Eligible'", + "o1-3": "'Disqualified due to political activity'" + }, + { + "_id": "r1-7", + "_description": "Insufficient Charitable Focus", + "i1-3": "< 85", + "o1-1": "'Non-exempt'", + "o1-2": "'Not Eligible'", + "o1-3": "'Insufficient focus on charitable activities'" + }, + { + "_id": "r1-8", + "_description": "Default Rule", + "i1-1": "", + "i1-2": "", + "i1-3": "", + "i1-4": "", + "o1-1": "'Requires Further Review'", + "o1-2": "'Pending'", + "o1-3": "'Organization requires manual review'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Organization Type", + "field": "organizationType" + }, + { + "id": "i1-2", + "name": "Political Activity", + "field": "politicalActivity" + }, + { + "id": "i1-3", + "name": "Charitable Activities Percentage", + "field": "charitableActivitiesPercentage" + }, + { + "id": "i1-4", + "name": "Public Support Percentage", + "field": "publicSupportPercentage" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Classification", + "field": "result.classification" + }, + { + "id": "o1-2", + "name": "Status", + "field": "result.status" + }, + { + "id": "o1-3", + "name": "Explanation", + "field": "result.explanation" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "taxExemptionEvaluation", + "position": { + "x": 430, + "y": 124.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "s1-1", + "condition": "result.classification == '501(c)(3)'", + "isDefault": false + }, + { + "id": "s1-2", + "condition": "", + "isDefault": true + } + ] + }, + "id": "sw1", + "name": "requiresAdditionalClassification", + "position": { + "x": 750, + "y": 124.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "result.annualFilingRequirement", + "value": "annualRevenue < 50000 ? '990-N' : annualRevenue < 200000 ? '990-EZ' : '990'" + }, + { + "id": "e1-2", + "key": "result.publicDisclosureRequired", + "value": "true" + }, + { + "id": "e1-3", + "key": "result.effectiveDate", + "value": "'2025-03-20'" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "exemptRequirements", + "position": { + "x": 1070, + "y": 75.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e2-1", + "key": "result.nextSteps", + "value": "result.status == 'Not Eligible' ? 'Organization must restructure to meet eligibility requirements' : 'Submit additional documentation for manual review'" + }, + { + "id": "e2-2", + "key": "result.appealDeadline", + "value": "'2025-05-19'" + }, + { + "id": "e2-3", + "key": "result.alternativeOptions", + "value": "organizationType == 'nonprofit' ? 'Consider 501(c)(4) or 501(c)(6) classification' : ''" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex2", + "name": "nonExemptGuidance", + "position": { + "x": 1070, + "y": 173.5 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "dt1", + "targetId": "sw1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "sw1", + "targetId": "ex1", + "sourceHandle": "s1-1", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "sw1", + "targetId": "ex2", + "sourceHandle": "s1-2", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/traffic-violation-penalty-calculator.json b/test-data/graphs/traffic-violation-penalty-calculator.json new file mode 100644 index 00000000..b03eba33 --- /dev/null +++ b/test-data/graphs/traffic-violation-penalty-calculator.json @@ -0,0 +1,436 @@ +{ + "tests": [ + { + "input": { + "violation": { + "type": "speeding", + "speed_over_limit": 25, + "in_school_zone": true, + "date": "2025-03-15T14:30:00Z", + "location": "Main St & 5th Ave" + }, + "driver": { + "license_number": "DL123456789", + "previous_violations": 1, + "license_issue_date": "2020-06-15" + } + }, + "output": { + "assessment": { + "base_fine": 150, + "base_points": 3, + "final_fine": 180, + "final_points": 3, + "license_suspension_recommended": false, + "payment_deadline_days": 30, + "risk_level": "medium", + "severity": "moderate" + }, + "driver": { + "license_issue_date": "2020-06-15", + "license_number": "DL123456789", + "previous_violations": 1 + }, + "violation": { + "date": "2025-03-15T14:30:00Z", + "in_school_zone": true, + "location": "Main St & 5th Ave", + "speed_over_limit": 25, + "type": "speeding" + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "'speeding'", + "i2": "> 30", + "o1": "'severe'", + "o2": "4", + "o3": "300" + }, + { + "_id": "rule2", + "i1": "'speeding'", + "i2": "> 15", + "o1": "'moderate'", + "o2": "3", + "o3": "150" + }, + { + "_id": "rule3", + "i1": "'speeding'", + "i2": "", + "o1": "'minor'", + "o2": "2", + "o3": "75" + }, + { + "_id": "rule4", + "i1": "'running_red_light'", + "i2": "", + "o1": "'moderate'", + "o2": "3", + "o3": "200" + }, + { + "_id": "rule5", + "i1": "'illegal_turn'", + "i2": "", + "o1": "'minor'", + "o2": "2", + "o3": "100" + }, + { + "_id": "rule6", + "i1": "'dui'", + "i2": "", + "o1": "'severe'", + "o2": "6", + "o3": "500" + }, + { + "_id": "rule7", + "i1": "'driving_without_license'", + "i2": "", + "o1": "'moderate'", + "o2": "3", + "o3": "250" + }, + { + "_id": "rule8", + "i1": "'reckless_driving'", + "i2": "", + "o1": "'severe'", + "o2": "5", + "o3": "350" + }, + { + "_id": "rule9", + "i1": "", + "i2": "", + "o1": "'minor'", + "o2": "1", + "o3": "50" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Violation Type", + "field": "violation.type" + }, + { + "id": "i2", + "name": "Speed Over Limit", + "field": "violation.speed_over_limit" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Severity", + "field": "assessment.severity" + }, + { + "id": "o2", + "name": "Points", + "field": "assessment.base_points" + }, + { + "id": "o3", + "name": "Base Fine", + "field": "assessment.base_fine" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "violation_classification", + "name": "classify_violation", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "pc1", + "i1": "'severe'", + "i2": "> 2", + "i3": "true", + "o1": "assessment.base_fine * 2", + "o2": "assessment.base_points * 1.5", + "o3": "true" + }, + { + "_id": "pc2", + "i1": "'severe'", + "i2": "", + "i3": "", + "o1": "assessment.base_fine * 1.5", + "o2": "assessment.base_points", + "o3": "false" + }, + { + "_id": "pc3", + "i1": "'moderate'", + "i2": "> 2", + "i3": "", + "o1": "assessment.base_fine * 1.25", + "o2": "assessment.base_points * 1.25", + "o3": "false" + }, + { + "_id": "pc4", + "i1": "'moderate'", + "i2": "", + "i3": "true", + "o1": "assessment.base_fine * 1.2", + "o2": "assessment.base_points", + "o3": "false" + }, + { + "_id": "pc5", + "i1": "'minor'", + "i2": "> 3", + "i3": "", + "o1": "assessment.base_fine * 1.1", + "o2": "assessment.base_points", + "o3": "false" + }, + { + "_id": "pc6", + "i1": "", + "i2": "", + "i3": "", + "o1": "assessment.base_fine", + "o2": "assessment.base_points", + "o3": "false" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Severity", + "field": "assessment.severity" + }, + { + "id": "i2", + "name": "Previous Violations", + "field": "driver.previous_violations" + }, + { + "id": "i3", + "name": "In School Zone", + "field": "violation.in_school_zone" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Final Fine", + "field": "assessment.final_fine" + }, + { + "id": "o2", + "name": "Final Points", + "field": "assessment.final_points" + }, + { + "id": "o3", + "name": "License Suspension Recommended", + "field": "assessment.license_suspension_recommended" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "penalty_calculation", + "name": "calculate_penalty", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "assessment.final_fine", + "value": "round(assessment.final_fine)" + }, + { + "id": "expr2", + "key": "assessment.final_points", + "value": "round(assessment.final_points)" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "final_assessment", + "name": "finalize_assessment", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "ra1", + "i1": ">= 5", + "i2": "'severe'", + "o1": "'high'", + "o2": "15" + }, + { + "_id": "ra2", + "i1": ">= 3", + "i2": "'severe'", + "o1": "'medium'", + "o2": "15" + }, + { + "_id": "ra3", + "i1": ">= 3", + "i2": "'moderate'", + "o1": "'medium'", + "o2": "30" + }, + { + "_id": "ra4", + "i1": ">= 3", + "i2": "'minor'", + "o1": "'medium'", + "o2": "45" + }, + { + "_id": "ra5", + "i1": "", + "i2": "'severe'", + "o1": "'low'", + "o2": "15" + }, + { + "_id": "ra6", + "i1": "", + "i2": "'moderate'", + "o1": "'low'", + "o2": "30" + }, + { + "_id": "ra7", + "i1": "", + "i2": "'minor'", + "o1": "'low'", + "o2": "45" + }, + { + "_id": "ra8", + "i1": "", + "i2": "", + "o1": "'low'", + "o2": "45" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Final Points", + "field": "assessment.final_points" + }, + { + "id": "i2", + "name": "Severity", + "field": "assessment.severity" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Risk Level", + "field": "assessment.risk_level" + }, + { + "id": "o2", + "name": "Payment Deadline Days", + "field": "assessment.payment_deadline_days" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "risk_assessment", + "name": "assess_risk_and_deadlines", + "position": { + "x": 1390, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "violation_classification", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "violation_classification", + "targetId": "penalty_calculation", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "penalty_calculation", + "targetId": "final_assessment", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "final_assessment", + "targetId": "risk_assessment", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/transaction-compliance-classifier.json b/test-data/graphs/transaction-compliance-classifier.json new file mode 100644 index 00000000..15d1c113 --- /dev/null +++ b/test-data/graphs/transaction-compliance-classifier.json @@ -0,0 +1,525 @@ +{ + "tests": [ + { + "input": { + "transaction": { + "id": "TX123456789", + "type": "cash_deposit", + "amount": 15000, + "date": "2025-03-15T10:30:00Z", + "currency": "USD", + "description": "Business cash deposit", + "high_risk_country": false, + "structuring_suspected": false + }, + "customer": { + "id": "CUST98765", + "name": "Acme Corporation", + "type": "business", + "jurisdiction": "US", + "kyc_verified": true, + "high_risk": false, + "suspicious_activity_count": 0, + "normal_activity_patterns": [ + "cash_deposit", + "domestic_wire", + "check_deposit" + ], + "account_opening_date": "2020-01-15", + "risk_category": "medium" + } + }, + "output": { + "has_compliance_flags": false, + "report_instructions": "File FinCEN Form 112 within 24 hours", + "reporting_deadline": 1743330600, + "reporting_status": "urgent_filing_required", + "requires_immediate_filing": true + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "'cash_deposit'", + "i1-2": "> 10000", + "o1-1": "'high_priority'", + "o1-2": "'CTR'" + }, + { + "_id": "r1-2", + "i1-1": "'international_wire'", + "i1-2": "> 3000", + "o1-1": "'medium_priority'", + "o1-2": "'FBAR'" + }, + { + "_id": "r1-3", + "i1-1": "'securities_trade'", + "i1-2": "> 5000", + "o1-1": "'medium_priority'", + "o1-2": "'SEC_REPORT'" + }, + { + "_id": "r1-4", + "i1-1": "'crypto_transaction'", + "i1-2": "> 3000", + "o1-1": "'high_priority'", + "o1-2": "'CRYPTO_SAR'" + }, + { + "_id": "r1-5", + "i1-1": "'structured_deposit'", + "i1-2": "", + "o1-1": "'high_priority'", + "o1-2": "'SAR'" + }, + { + "_id": "r1-6", + "i1-1": "'domestic_wire'", + "i1-2": "> 10000", + "o1-1": "'low_priority'", + "o1-2": "'WIRE_REPORT'" + }, + { + "_id": "r1-7", + "i1-1": "", + "i1-2": "", + "o1-1": "'standard'", + "o1-2": "'STANDARD'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Transaction Type", + "field": "transaction.type" + }, + { + "id": "i1-2", + "name": "Amount", + "field": "transaction.amount" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Priority", + "field": "classification.priority" + }, + { + "id": "o1-2", + "name": "Report Type", + "field": "classification.report_type" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "transaction_type", + "name": "classify_transaction", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r2-1", + "i2-1": "'US'", + "i2-2": "'CTR'", + "o2-1": "15", + "o2-2": "'FinCEN Form 112'", + "o2-3": "15" + }, + { + "_id": "r2-2", + "i2-1": "'US'", + "i2-2": "'SAR'", + "o2-1": "30", + "o2-2": "'FinCEN Form 111'", + "o2-3": "30" + }, + { + "_id": "r2-3", + "i2-1": "'EU'", + "i2-2": "'CTR', 'SAR'", + "o2-1": "10", + "o2-2": "'EU Suspicious Transaction Report'", + "o2-3": "10" + }, + { + "_id": "r2-4", + "i2-1": "'UK'", + "i2-2": "'CTR', 'SAR'", + "o2-1": "7", + "o2-2": "'NCA SAR'", + "o2-3": "10" + }, + { + "_id": "r2-5", + "i2-1": "", + "i2-2": "", + "o2-1": "30", + "o2-2": "'Standard Reporting Form'", + "o2-3": "5" + } + ], + "inputs": [ + { + "id": "i2-1", + "name": "Jurisdiction", + "field": "customer.jurisdiction" + }, + { + "id": "i2-2", + "name": "Report Type", + "field": "classification.report_type" + } + ], + "outputs": [ + { + "id": "o2-1", + "name": "Days to Report", + "field": "reporting.days_to_report" + }, + { + "id": "o2-2", + "name": "Form Name", + "field": "reporting.form_name" + }, + { + "id": "o2-3", + "name": "Jurisdiction Score", + "field": "risk.jurisdiction_score" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "jurisdiction_rules", + "name": "apply_jurisdiction_rules", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "base_risk_score", + "value": "0" + }, + { + "id": "e1-2", + "key": "amount_score", + "value": "transaction.amount > 50000 ? 25 : (transaction.amount > 10000 ? 15 : (transaction.amount > 5000 ? 10 : 5))" + }, + { + "id": "e1-3", + "key": "priority_score", + "value": "classification.priority == 'high_priority' ? 25 : (classification.priority == 'medium_priority' ? 15 : 5)" + }, + { + "id": "e1-4", + "key": "customer_score", + "value": "customer.high_risk == true ? 20 : 0" + }, + { + "id": "e1-5", + "key": "transaction_history_score", + "value": "customer.suspicious_activity_count > 2 ? 20 : (customer.suspicious_activity_count > 0 ? 10 : 0)" + }, + { + "id": "e1-6", + "key": "total_risk_score", + "value": "$.base_risk_score + $.amount_score + $.priority_score + $.customer_score + $.transaction_history_score + risk.jurisdiction_score" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "risk_assessment", + "name": "calculate_risk_score", + "position": { + "x": 1070, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r3-1", + "i3-1": "> 75", + "i3-2": "'high_priority'", + "o3-1": "true", + "o3-2": "'Requires immediate review - High risk score and priority'" + }, + { + "_id": "r3-2", + "i3-1": "> 60", + "i3-2": "", + "o3-1": "true", + "o3-2": "'High risk score requires compliance review'" + }, + { + "_id": "r3-3", + "i3-1": "[40..60]", + "i3-2": "'high_priority'", + "o3-1": "true", + "o3-2": "'Medium risk score with high priority requires review'" + }, + { + "_id": "r3-4", + "i3-1": "[40..60]", + "i3-2": "", + "o3-1": "false", + "o3-2": "'Medium risk score - standard monitoring'" + }, + { + "_id": "r3-5", + "i3-1": "", + "i3-2": "", + "o3-1": "false", + "o3-2": "'Standard monitoring - no flags'" + } + ], + "inputs": [ + { + "id": "i3-1", + "name": "Risk Score", + "field": "total_risk_score" + }, + { + "id": "i3-2", + "name": "Priority", + "field": "classification.priority" + } + ], + "outputs": [ + { + "id": "o3-1", + "name": "Requires Review", + "field": "compliance.requires_review" + }, + { + "id": "o3-2", + "name": "Review Reason", + "field": "compliance.review_reason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single", + "passThorough": false + }, + "id": "threshold_checks", + "name": "regulatory_thresholds", + "position": { + "x": 1390, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "collect", + "rules": [ + { + "_id": "r4-1", + "i4-1": "transaction.amount > 10000", + "i4-2": "customer.kyc_verified != true", + "o4-1": "true", + "o4-2": "'KYC_INCOMPLETE'", + "o4-3": "'Customer KYC verification incomplete for large transaction'" + }, + { + "_id": "r4-2", + "i4-1": "transaction.amount > 5000", + "i4-2": "transaction.high_risk_country == true", + "o4-1": "true", + "o4-2": "'HIGH_RISK_JURISDICTION'", + "o4-3": "'Transaction involves high-risk jurisdiction'" + }, + { + "_id": "r4-3", + "i4-1": "customer.suspicious_activity_count > 0", + "i4-2": "transaction.amount > 3000", + "o4-1": "true", + "o4-2": "'PATTERN_ALERT'", + "o4-3": "'Multiple suspicious activities detected with customer'" + }, + { + "_id": "r4-4", + "i4-1": "transaction.structuring_suspected == true", + "i4-2": "", + "o4-1": "true", + "o4-2": "'STRUCTURING'", + "o4-3": "'Potential structuring activity detected'" + }, + { + "_id": "r4-5", + "i4-1": "transaction.amount > 50000", + "i4-2": "!contains(customer.normal_activity_patterns ?? [], transaction.type)", + "o4-1": "true", + "o4-2": "'UNUSUAL_ACTIVITY'", + "o4-3": "'Transaction outside of normal customer activity patterns'" + } + ], + "inputs": [ + { + "id": "i4-1", + "name": "Condition 1" + }, + { + "id": "i4-2", + "name": "Condition 2" + } + ], + "outputs": [ + { + "id": "o4-1", + "name": "Flag Raised", + "field": "raised" + }, + { + "id": "o4-2", + "name": "Flag Type", + "field": "type" + }, + { + "id": "o4-3", + "name": "Flag Description", + "field": "description" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": "compliance.flags", + "executionMode": "single", + "passThorough": false + }, + "id": "compliance_flags", + "name": "identify_compliance_issues", + "position": { + "x": 1710, + "y": 115 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e2-1", + "key": "reporting_deadline", + "value": "date(transaction.date) + (reporting.days_to_report * 86400)" + }, + { + "id": "e2-2", + "key": "has_compliance_flags", + "value": "len(compliance.flags ?? []) > 0" + }, + { + "id": "e2-3", + "key": "requires_immediate_filing", + "value": "compliance.requires_review == true or ($.has_compliance_flags and classification.priority == 'high_priority')" + }, + { + "id": "e2-4", + "key": "reporting_status", + "value": "$.requires_immediate_filing ? 'urgent_filing_required' : ($.has_compliance_flags ? 'filing_required' : 'standard_reporting')" + }, + { + "id": "e2-5", + "key": "report_instructions", + "value": "$.requires_immediate_filing ? 'File ' + reporting.form_name + ' within 24 hours' : 'File ' + reporting.form_name + ' within ' + string(reporting.days_to_report) + ' days'" + } + ], + "passThrough": false, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "reporting_requirements", + "name": "determine_reporting_requirements", + "position": { + "x": 2030, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "transaction_type", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "transaction_type", + "targetId": "jurisdiction_rules", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "jurisdiction_rules", + "targetId": "risk_assessment", + "type": "edge" + }, + { + "id": "edge4", + "sourceId": "risk_assessment", + "targetId": "threshold_checks", + "type": "edge" + }, + { + "id": "edge5", + "sourceId": "threshold_checks", + "targetId": "compliance_flags", + "type": "edge" + }, + { + "id": "edge6", + "sourceId": "compliance_flags", + "targetId": "reporting_requirements", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/vehicle-claims-resolution.json b/test-data/graphs/vehicle-claims-resolution.json new file mode 100644 index 00000000..a79efa32 --- /dev/null +++ b/test-data/graphs/vehicle-claims-resolution.json @@ -0,0 +1,310 @@ +{ + "tests": [ + { + "input": { + "claim": { + "id": "CL-20250318-001", + "damagePercentage": 65 + }, + "vehicle": { + "make": "Toyota", + "model": "Camry", + "year": 2015, + "ageYears": 10 + }, + "parts": { + "status": "limited" + } + }, + "output": { + "assessment": { + "damageLevel": "severe", + "isTotalLoss": false + }, + "claim": { + "damagePercentage": 65, + "id": "CL-20250318-001" + }, + "parts": { + "availability": "available", + "status": "limited" + }, + "recommendation": { + "explanation": "Severe damage with obtainable parts; repair recommended", + "method": "repair" + }, + "vehicle": { + "ageYears": 10, + "make": "Toyota", + "model": "Camry", + "year": 2015 + } + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": ">= 80", + "o1": "'total_loss'", + "o2": "true" + }, + { + "_id": "rule2", + "i1": ">= 60", + "o1": "'severe'", + "o2": "false" + }, + { + "_id": "rule3", + "i1": ">= 30", + "o1": "'moderate'", + "o2": "false" + }, + { + "_id": "rule4", + "i1": "", + "o1": "'minor'", + "o2": "false" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Damage Percentage", + "field": "claim.damagePercentage" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Damage Assessment", + "field": "assessment.damageLevel" + }, + { + "id": "o2", + "name": "Is Total Loss", + "field": "assessment.isTotalLoss" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "assessDamage", + "name": "assessDamage", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "> 10", + "i2": "'discontinued'", + "o1": "'unavailable'" + }, + { + "_id": "rule2", + "i1": "> 10", + "i2": "'limited'", + "o1": "'delayed'" + }, + { + "_id": "rule3", + "i1": "> 10", + "i2": "'available'", + "o1": "'available'" + }, + { + "_id": "rule4", + "i1": "<= 10", + "i2": "", + "o1": "'available'" + }, + { + "_id": "rule5", + "i1": "", + "i2": "", + "o1": "'available'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Vehicle Age", + "field": "vehicle.ageYears" + }, + { + "id": "i2", + "name": "Parts Status", + "field": "parts.status" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Parts Availability", + "field": "parts.availability" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "checkPartsAvailability", + "name": "checkPartsAvailability", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "'total_loss'", + "i2": "", + "i3": "", + "o1": "'cash_settlement'", + "o2": "'Vehicle is a total loss; cash settlement recommended'" + }, + { + "_id": "rule2", + "i1": "'severe'", + "i2": "'unavailable'", + "i3": "> 8", + "o1": "'cash_settlement'", + "o2": "'Severe damage with unavailable parts for older vehicle; cash settlement recommended'" + }, + { + "_id": "rule3", + "i1": "'severe'", + "i2": "'unavailable'", + "i3": "<= 8", + "o1": "'replacement'", + "o2": "'Severe damage with unavailable parts for newer vehicle; replacement recommended'" + }, + { + "_id": "rule4", + "i1": "'severe'", + "i2": "'delayed', 'available'", + "i3": "", + "o1": "'repair'", + "o2": "'Severe damage with obtainable parts; repair recommended'" + }, + { + "_id": "rule5", + "i1": "'moderate'", + "i2": "'unavailable'", + "i3": "> 6", + "o1": "'cash_settlement'", + "o2": "'Moderate damage with unavailable parts for older vehicle; cash settlement recommended'" + }, + { + "_id": "rule6", + "i1": "'moderate'", + "i2": "'delayed', 'available'", + "i3": "", + "o1": "'repair'", + "o2": "'Moderate damage with obtainable parts; repair recommended'" + }, + { + "_id": "rule7", + "i1": "'minor'", + "i2": "", + "i3": "", + "o1": "'repair'", + "o2": "'Minor damage; repair recommended'" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Damage Level", + "field": "assessment.damageLevel" + }, + { + "id": "i2", + "name": "Parts Availability", + "field": "parts.availability" + }, + { + "id": "i3", + "name": "Vehicle Age", + "field": "vehicle.ageYears" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Repair Method", + "field": "recommendation.method" + }, + { + "id": "o2", + "name": "Explanation", + "field": "recommendation.explanation" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "determineRepairMethod", + "name": "determineRepairMethod", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "assessDamage", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "assessDamage", + "targetId": "checkPartsAvailability", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "checkPartsAvailability", + "targetId": "determineRepairMethod", + "type": "edge" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/warehouse-cross-docking.json b/test-data/graphs/warehouse-cross-docking.json new file mode 100644 index 00000000..ad14abda --- /dev/null +++ b/test-data/graphs/warehouse-cross-docking.json @@ -0,0 +1,313 @@ +{ + "tests": [ + { + "input": { + "inboundShipmentId": "IN-12345", + "inboundShipmentTime": "2025-03-19T10:00:00Z", + "outboundShipmentTime": "2025-03-20T09:00:00Z", + "matchingOutboundOrders": [ + { + "orderId": "ORD-789", + "customerPriority": "standard", + "destinationZone": "East" + }, + { + "orderId": "ORD-790", + "customerPriority": "premium", + "destinationZone": "East" + } + ], + "inboundShipmentItems": [ + { + "sku": "ITEM-001", + "quantity": 50, + "category": "Electronics" + }, + { + "sku": "ITEM-002", + "quantity": 30, + "category": "Home Goods" + } + ], + "currentStorageUsed": 7500, + "totalStorageCapacity": 10000, + "crossDockingBayAssignment": "Bay-E4" + }, + "output": { + "crossDockDecision": "cross-dock", + "crossDockingBayAssignment": "Bay-E4", + "currentStorageUsed": 7500, + "decisionReason": "Matching orders available within 48 hours", + "dockingBay": "Bay-E4", + "estimatedProcessingTime": 30, + "hasMatchingOutboundOrders": true, + "inboundShipmentId": "IN-12345", + "inboundShipmentItems": [ + { + "category": "Electronics", + "quantity": 50, + "sku": "ITEM-001" + }, + { + "category": "Home Goods", + "quantity": 30, + "sku": "ITEM-002" + } + ], + "inboundShipmentTime": "2025-03-19T10:00:00Z", + "matchingOutboundOrders": [ + { + "customerPriority": "standard", + "destinationZone": "East", + "orderId": "ORD-789" + }, + { + "customerPriority": "premium", + "destinationZone": "East", + "orderId": "ORD-790" + } + ], + "outboundShipmentTime": "2025-03-20T09:00:00Z", + "priority": "normal", + "timeDifferenceHours": 23, + "totalStorageCapacity": 10000, + "warehouseCapacityPercentage": 75 + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "ip1", + "name": "shipmentRequest", + "position": { + "x": 110, + "y": 173.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e1-1", + "key": "hasMatchingOutboundOrders", + "value": "len(matchingOutboundOrders) > 0" + }, + { + "id": "e1-2", + "key": "timeDifferenceHours", + "value": "(date(outboundShipmentTime) - date(inboundShipmentTime)) / 3600" + }, + { + "id": "e1-3", + "key": "warehouseCapacityPercentage", + "value": "(currentStorageUsed / totalStorageCapacity) * 100" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex1", + "name": "calculateMetrics", + "position": { + "x": 430, + "y": 173.5 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "r1-1", + "i1-1": "true", + "i1-2": "[0..24]", + "i1-3": "<= 36", + "o1-1": "'cross-dock'", + "o1-2": "'Matching orders available within 24 hours with sufficient capacity'" + }, + { + "_id": "r1-2", + "i1-1": "true", + "i1-2": "[0..48]", + "i1-3": "<= 80", + "o1-1": "'cross-dock'", + "o1-2": "'Matching orders available within 48 hours'" + }, + { + "_id": "r1-3", + "i1-1": "true", + "i1-2": "> 48", + "i1-3": ">= 90", + "o1-1": "'cross-dock'", + "o1-2": "'High warehouse capacity, cross-dock to save space'" + }, + { + "_id": "r1-4", + "i1-1": "true", + "i1-2": "> 72", + "i1-3": "", + "o1-1": "'store'", + "o1-2": "'Matching orders but time difference too large'" + }, + { + "_id": "r1-5", + "i1-1": "false", + "i1-2": "", + "i1-3": "", + "o1-1": "'store'", + "o1-2": "'No matching outbound orders'" + } + ], + "inputs": [ + { + "id": "i1-1", + "name": "Has Matching Orders", + "field": "hasMatchingOutboundOrders" + }, + { + "id": "i1-2", + "name": "Time Difference (hours)", + "field": "timeDifferenceHours" + }, + { + "id": "i1-3", + "name": "Warehouse Capacity (%)", + "field": "warehouseCapacityPercentage" + } + ], + "outputs": [ + { + "id": "o1-1", + "name": "Decision", + "field": "crossDockDecision" + }, + { + "id": "o1-2", + "name": "Reason", + "field": "decisionReason" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "dt1", + "name": "crossDockingDecision", + "position": { + "x": 750, + "y": 173.5 + } + }, + { + "type": "switchNode", + "content": { + "hitPolicy": "first", + "statements": [ + { + "id": "s1-1", + "condition": "crossDockDecision == 'cross-dock'", + "isDefault": false + }, + { + "id": "s1-2", + "condition": "", + "isDefault": true + } + ] + }, + "id": "sw1", + "name": "handleCrossDocking", + "position": { + "x": 1070, + "y": 173.5 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "e2-1", + "key": "dockingBay", + "value": "crossDockingBayAssignment" + }, + { + "id": "e2-2", + "key": "estimatedProcessingTime", + "value": "30" + }, + { + "id": "e2-3", + "key": "priority", + "value": "timeDifferenceHours < 12 ? 'high' : 'normal'" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "ex2", + "name": "assignCrossDockingDetails", + "position": { + "x": 1390, + "y": 173.5 + } + }, + { + "type": "outputNode", + "content": { + "schema": "" + }, + "id": "e1a7d99b-255e-47a2-929f-642fc0e7efc5", + "name": "response", + "position": { + "x": 1390, + "y": 305 + } + } + ], + "edges": [ + { + "id": "ed1", + "sourceId": "ip1", + "targetId": "ex1", + "type": "edge" + }, + { + "id": "ed2", + "sourceId": "ex1", + "targetId": "dt1", + "type": "edge" + }, + { + "id": "ed3", + "sourceId": "dt1", + "targetId": "sw1", + "type": "edge" + }, + { + "id": "ed4", + "sourceId": "sw1", + "targetId": "ex2", + "sourceHandle": "s1-1", + "type": "edge" + }, + { + "id": "7d282229-bce6-47a6-a68d-ed867787a674", + "sourceId": "sw1", + "type": "edge", + "targetId": "e1a7d99b-255e-47a2-929f-642fc0e7efc5", + "sourceHandle": "s1-2" + } + ] +} \ No newline at end of file diff --git a/test-data/graphs/warehouse-storage-location.json b/test-data/graphs/warehouse-storage-location.json new file mode 100644 index 00000000..62cb8f3a --- /dev/null +++ b/test-data/graphs/warehouse-storage-location.json @@ -0,0 +1,345 @@ +{ + "tests": [ + { + "input": { + "product": { + "id": "PRD-12345", + "name": "Gaming Laptop XZ5000", + "dimensions": { + "length": 40, + "width": 30, + "height": 10, + "unit": "cm" + }, + "weight": { + "value": 3.5, + "unit": "kg" + }, + "monthlyUnits": 2500, + "turnoverRate": 0.65, + "picksPerDay": 12, + "fragilityScore": 4, + "specialHandling": false, + "hazardous": false + } + }, + "output": { + "allocatedLocation": "prime-picking-area-pallet-rack-bottom", + "allocation": { + "priority": 3, + "storageType": "pallet-rack-bottom", + "warehouseZone": "prime-picking-area" + }, + "classification": { + "fastMoving": true, + "volumeCategory": "medium-volume" + }, + "pickingEfficiencyScore": 7, + "product": { + "dimensions": { + "height": 10, + "length": 40, + "unit": "cm", + "width": 30 + }, + "fragilityScore": 4, + "hazardous": false, + "id": "PRD-12345", + "monthlyUnits": 2500, + "name": "Gaming Laptop XZ5000", + "picksPerDay": 12, + "specialHandling": false, + "turnoverRate": 0.65, + "weight": { + "unit": "kg", + "value": 3.5 + } + }, + "recommendedQuantity": 1250, + "replenishmentFrequency": "weekly" + } + } + ], + "nodes": [ + { + "type": "inputNode", + "content": { + "schema": "" + }, + "id": "input", + "name": "request", + "position": { + "x": 110, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "> 5000", + "i2": "> 0.8", + "i3": "> 15", + "o1": "'high-volume'", + "o2": "true" + }, + { + "_id": "rule2", + "i1": "> 1000", + "i2": "> 0.5", + "i3": "> 10", + "o1": "'medium-volume'", + "o2": "true" + }, + { + "_id": "rule3", + "i1": "> 1000", + "i2": "< 0.5", + "i3": "< 10", + "o1": "'medium-volume'", + "o2": "false" + }, + { + "_id": "rule4", + "i1": "< 1000", + "i2": "> 0.7", + "i3": "> 8", + "o1": "'low-volume-fast'", + "o2": "true" + }, + { + "_id": "rule5", + "i1": "", + "i2": "", + "i3": "", + "o1": "'low-volume-standard'", + "o2": "false" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Monthly Units", + "field": "product.monthlyUnits" + }, + { + "id": "i2", + "name": "Turnover Rate", + "field": "product.turnoverRate" + }, + { + "id": "i3", + "name": "Picks Per Day", + "field": "product.picksPerDay" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Volume Category", + "field": "classification.volumeCategory" + }, + { + "id": "o2", + "name": "Fast Moving", + "field": "classification.fastMoving" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "productClassification", + "name": "classifyProduct", + "position": { + "x": 430, + "y": 114 + } + }, + { + "type": "decisionTableNode", + "content": { + "hitPolicy": "first", + "rules": [ + { + "_id": "rule1", + "i1": "'high-volume'", + "i2": "true", + "i3": "> 3", + "o1": "'floor-level'", + "o2": "'prime-picking-area'", + "o3": "1" + }, + { + "_id": "rule2", + "i1": "'high-volume'", + "i2": "true", + "i3": "< 3", + "o1": "'pallet-rack-bottom'", + "o2": "'prime-picking-area'", + "o3": "2" + }, + { + "_id": "rule3", + "i1": "'medium-volume'", + "i2": "true", + "i3": "> 2", + "o1": "'pallet-rack-bottom'", + "o2": "'prime-picking-area'", + "o3": "3" + }, + { + "_id": "rule4", + "i1": "'medium-volume'", + "i2": "false", + "i3": "> 2", + "o1": "'pallet-rack-middle'", + "o2": "'standard-picking-area'", + "o3": "4" + }, + { + "_id": "rule5", + "i1": "'medium-volume'", + "i2": "false", + "i3": "< 2", + "o1": "'pallet-rack-upper'", + "o2": "'standard-picking-area'", + "o3": "5" + }, + { + "_id": "rule6", + "i1": "'low-volume-fast'", + "i2": "true", + "i3": "", + "o1": "'bin-shelving-middle'", + "o2": "'standard-picking-area'", + "o3": "6" + }, + { + "_id": "rule7", + "i1": "'low-volume-standard'", + "i2": "false", + "i3": "< 1", + "o1": "'bin-shelving-upper'", + "o2": "'overflow-area'", + "o3": "7" + }, + { + "_id": "rule8", + "i1": "", + "i2": "", + "i3": "", + "o1": "'bin-shelving-standard'", + "o2": "'standard-picking-area'", + "o3": "8" + } + ], + "inputs": [ + { + "id": "i1", + "name": "Volume Category", + "field": "classification.volumeCategory" + }, + { + "id": "i2", + "name": "Fast Moving", + "field": "classification.fastMoving" + }, + { + "id": "i3", + "name": "Fragility", + "field": "product.fragilityScore" + } + ], + "outputs": [ + { + "id": "o1", + "name": "Storage Type", + "field": "allocation.storageType" + }, + { + "id": "o2", + "name": "Warehouse Zone", + "field": "allocation.warehouseZone" + }, + { + "id": "o3", + "name": "Priority", + "field": "allocation.priority" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "locationAssignment", + "name": "assignLocation", + "position": { + "x": 750, + "y": 114 + } + }, + { + "type": "expressionNode", + "content": { + "expressions": [ + { + "id": "expr1", + "key": "allocatedLocation", + "value": "allocation.warehouseZone + '-' + allocation.storageType" + }, + { + "id": "expr2", + "key": "pickingEfficiencyScore", + "value": "classification.fastMoving ? 10 - allocation.priority : 5 - allocation.priority" + }, + { + "id": "expr3", + "key": "recommendedQuantity", + "value": "product.monthlyUnits / 2" + }, + { + "id": "expr4", + "key": "replenishmentFrequency", + "value": "product.turnoverRate > 0.7 ? 'daily' : product.turnoverRate > 0.4 ? 'weekly' : 'monthly'" + } + ], + "passThrough": true, + "inputField": null, + "outputPath": null, + "executionMode": "single" + }, + "id": "finalAllocation", + "name": "finalizeAllocation", + "position": { + "x": 1070, + "y": 114 + } + } + ], + "edges": [ + { + "id": "edge1", + "sourceId": "input", + "targetId": "productClassification", + "type": "edge" + }, + { + "id": "edge2", + "sourceId": "productClassification", + "targetId": "locationAssignment", + "type": "edge" + }, + { + "id": "edge3", + "sourceId": "locationAssignment", + "targetId": "finalAllocation", + "type": "edge" + } + ] +} \ No newline at end of file From 7bc623a15efa5f006511145a947edd139de9c516 Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 20 Aug 2025 12:42:34 +0200 Subject: [PATCH 07/14] mock time; update snapshots --- core/engine/Cargo.toml | 2 + core/engine/src/handler/expression/mod.rs | 4 +- core/engine/tests/engine.rs | 10 + ...engine__account-dormancy-management_0.snap | 32 +- ...ne__affiliate-commission-calculator_0.snap | 9 +- ...airline-loyalty-points-calculations_0.snap | 9 +- ...engine__airline-upgrade-eligibility_0.snap | 9 +- ...engine__application-risk-assessment_0.snap | 15 +- ...__auto-insurance-premium-calculator_0.snap | 9 +- .../engine__booking-fraud-detection_0.snap | 11 +- ...ine__booking-personalization-system_0.snap | 11 +- ...engine__care-team-assignment-system_0.snap | 14 +- ...gine__cellular-data-rollover-system_0.snap | 15 +- .../engine__claim-validation-system_0.snap | 6 +- .../engine__clinical-pathway-selection_0.snap | 21 +- ...engine__clinical-treatment-protocol_0.snap | 11 +- ...clinical-trial-eligibility-screener_0.snap | 569 ------- .../engine__credit-limit-adjustment_0.snap | 9 +- ...engine__customer-eligibility-engine_0.snap | 10 +- .../engine__customer-lifetime-value_0.snap | 21 +- ...ustomer-onboarding-kyc-verification_0.snap | 19 +- .../engine__delivery-route-optimizer_0.snap | 9 +- ...ngine__device-compatibility-checker_0.snap | 5 +- ...ne__disaster-relief-fund-allocation_0.snap | 6 +- ...ic-marketplace-comission-calculator_0.snap | 11 +- ...e__dynamic-shipping-cost-calculator_0.snap | 11 +- .../engine__dynamic-tarrif-engine_0.snap | 13 +- .../engine__dynamic-ticket-pricing_0.snap | 9 +- ...__environment-compliance-assessment_0.snap | 12 +- .../engine__expression-default_0.snap | 3 +- .../engine__expression-default_1.snap | 3 +- .../engine__expression-default_2.snap | 3 +- .../engine__expression-default_3.snap | 3 +- .../engine__expression-default_4.snap | 11 +- .../engine__expression-fields_0.snap | 2 +- .../engine__expression-fields_1.snap | 2 +- .../snapshots/engine__expression-loop_0.snap | 9 +- .../engine__expression-passthrough_0.snap | 3 +- .../engine__expression-passthrough_1.snap | 3 +- .../engine__expression-passthrough_2.snap | 3 +- .../engine__expression-passthrough_3.snap | 3 +- .../engine__expression-passthrough_4.snap | 3 +- .../engine__expression-table-map_0.snap | 9 +- .../engine__expression-table-map_1.snap | 6 +- .../engine__expression-table-map_2.snap | 9 +- .../engine__flash-sale-eligibility_0.snap | 8 +- ...e__flight-ancillary-recommendations_0.snap | 630 -------- ...ne__flight-dispatch-decision-system_0.snap | 23 +- ...ne__flight-rebooking-fee-calculator_0.snap | 3 +- .../engine__grant-funding-distribution_0.snap | 11 +- .../engine__import-duties-calculator_0.snap | 21 +- .../engine__insurance-agent-commission_0.snap | 3 +- ...gine__insurance-prior-authorization_0.snap | 11 +- ...engine__insurance-underwriting-risk_0.snap | 7 +- ...nternational-roaming-policy-manager_0.snap | 10 +- ...gine__last-mile-delivery-assignment_0.snap | 30 +- .../engine__legacy-plan-management_0.snap | 6 +- .../snapshots/engine__loan-approval_0.snap | 17 +- ...etplace-listing-verification-system_0.snap | 13 +- ...__marketplace-seller-grading-system_0.snap | 14 +- ...medical-appointment-priority-system_0.snap | 391 ----- ...ngine__medication-dosage-calculator_0.snap | 20 +- ..._municipal-permit-evaluation-system_0.snap | 10 +- .../snapshots/engine__nested-request_0.snap | 8 +- .../engine__online-checkin-eligibility_0.snap | 21 +- .../engine__order-consolidation-system_0.snap | 28 +- .../engine__partner-revenue-sharing_0.snap | 18 +- .../engine__patient-triage-system_0.snap | 2 +- ..._payment-routing-and-fee-calculator_0.snap | 29 +- .../engine__policy-discount-calculator_0.snap | 9 +- ...engine__policy-eligibility-analyzer_0.snap | 8 +- .../engine__portfolio-risk-monitor_0.snap | 1415 ----------------- ...ine__preventive-care-recommendation_0.snap | 298 ---- .../engine__product-listing-scoring_0.snap | 27 +- .../engine__realtime-fraud-detection_0.snap | 9 +- ...engine__regional-compliance-manager_0.snap | 11 +- .../engine__returns-and-refund-policy_0.snap | 10 +- .../engine__returns-processing-system_0.snap | 8 +- ...school-district-resource-allocation_0.snap | 9 +- .../engine__seat-map-optimization_0.snap | 13 +- .../engine__seller-approval-workflow_0.snap | 12 +- .../engine__seller-fee-calculator_0.snap | 9 +- ...service-level-agreement-enforcement_0.snap | 13 +- .../tests/snapshots/engine__set-fee_0.snap | 6 +- .../tests/snapshots/engine__set-fee_2.snap | 6 +- .../engine__shipping-carrier-selector_0.snap | 42 +- .../engine__supply-chain-risk_0.snap | 9 +- .../snapshots/engine__tax-exemption_0.snap | 6 +- ...raffic-violation-penalty-calculator_0.snap | 6 +- ...__transaction-compliance-classifier_0.snap | 29 +- .../engine__warehouse-cross-docking_0.snap | 15 +- .../engine__warehouse-storage-location_0.snap | 10 +- core/expression/src/vm/date/mod.rs | 24 +- core/expression/src/vm/helpers.rs | 5 +- test-data/graphs/booking-fraud-detection.json | 428 ----- .../clinical-trial-eligibility-screener.json | 502 ------ .../flight-ancillary-recommendations.json | 436 ----- .../marketplace-seller-grading-system.json | 436 ----- .../medical-appointment-priority-system.json | 446 ------ test-data/graphs/patient-triage-system.json | 406 ----- test-data/graphs/portfolio-risk-monitor.json | 588 ------- .../preventive-care-recommendation.json | 370 ----- 102 files changed, 660 insertions(+), 7262 deletions(-) delete mode 100644 core/engine/tests/snapshots/engine__clinical-trial-eligibility-screener_0.snap delete mode 100644 core/engine/tests/snapshots/engine__flight-ancillary-recommendations_0.snap delete mode 100644 core/engine/tests/snapshots/engine__medical-appointment-priority-system_0.snap delete mode 100644 core/engine/tests/snapshots/engine__portfolio-risk-monitor_0.snap delete mode 100644 core/engine/tests/snapshots/engine__preventive-care-recommendation_0.snap delete mode 100644 test-data/graphs/booking-fraud-detection.json delete mode 100644 test-data/graphs/clinical-trial-eligibility-screener.json delete mode 100644 test-data/graphs/flight-ancillary-recommendations.json delete mode 100644 test-data/graphs/marketplace-seller-grading-system.json delete mode 100644 test-data/graphs/medical-appointment-priority-system.json delete mode 100644 test-data/graphs/patient-triage-system.json delete mode 100644 test-data/graphs/portfolio-risk-monitor.json delete mode 100644 test-data/graphs/preventive-care-recommendation.json diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 49928701..ef4d93ac 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -29,9 +29,11 @@ zen-expression = { path = "../expression", version = "0.49.1" } zen-tmpl = { path = "../template", version = "0.49.1" } [dev-dependencies] +chrono = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } criterion = { workspace = true, features = ["async_tokio"] } insta = { version = "1.43", features = ["yaml", "redactions"] } +zen-expression = { path = "../expression", version = "0.49.1", features = ["time-override"] } [[bench]] harness = false diff --git a/core/engine/src/handler/expression/mod.rs b/core/engine/src/handler/expression/mod.rs index 372787e8..29af5f6d 100644 --- a/core/engine/src/handler/expression/mod.rs +++ b/core/engine/src/handler/expression/mod.rs @@ -15,7 +15,7 @@ pub struct ExpressionHandler { #[derive(Debug, Serialize)] struct ExpressionTrace { - result: String, + result: serde_json::Value, } impl ExpressionHandler { @@ -82,7 +82,7 @@ impl<'a> ExpressionHandlerInner<'a> { tmap.insert( &expression.key, ExpressionTrace { - result: serde_json::to_string(&value).unwrap_or("Error".to_owned()), + result: value.to_value(), }, ); } diff --git a/core/engine/tests/engine.rs b/core/engine/tests/engine.rs index e8997bd9..61ad0502 100644 --- a/core/engine/tests/engine.rs +++ b/core/engine/tests/engine.rs @@ -1,4 +1,5 @@ use crate::support::{create_fs_loader, load_raw_test_data, load_test_data, test_data_root}; +use chrono::{TimeZone, Utc}; use serde::Deserialize; use serde_json::json; use std::fs; @@ -11,6 +12,7 @@ use zen_engine::loader::{LoaderError, MemoryLoader}; use zen_engine::model::{DecisionContent, DecisionNode, DecisionNodeKind, FunctionNodeContent}; use zen_engine::Variable; use zen_engine::{DecisionEngine, EvaluationError, EvaluationOptions}; +use zen_expression::vm::UTC_OVERRIDE; mod support; @@ -223,6 +225,8 @@ async fn engine_switch_node() { #[tokio::test] #[cfg_attr(miri, ignore)] async fn engine_graph_tests() { + mock_datetime(); + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct TestCase { @@ -264,9 +268,15 @@ async fn engine_graph_tests() { } } +fn mock_datetime() { + *UTC_OVERRIDE.write().unwrap() = Some("2025-08-19T16:55:02.078Z".parse().unwrap()); +} + #[tokio::test] #[cfg_attr(miri, ignore)] async fn engine_snapshot_tests() { + mock_datetime(); + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct TestCase { diff --git a/core/engine/tests/snapshots/engine__account-dormancy-management_0.snap b/core/engine/tests/snapshots/engine__account-dormancy-management_0.snap index 4b1abeae..9e4a68bc 100644 --- a/core/engine/tests/snapshots/engine__account-dormancy-management_0.snap +++ b/core/engine/tests/snapshots/engine__account-dormancy-management_0.snap @@ -20,9 +20,9 @@ trace: customerPhone: "+15551234567" customerTier: premium daysSinceLastActivity: - "$serde_json::private::Number": "24054457" + "$serde_json::private::Number": "23993702" daysToThreshold: - "$serde_json::private::Number": "-24054277" + "$serde_json::private::Number": "-23993522" dormancyThreshold: "$serde_json::private::Number": "180" lastActivityDate: 2024-11-15 @@ -42,9 +42,9 @@ trace: customerPhone: "+15551234567" customerTier: premium daysSinceLastActivity: - "$serde_json::private::Number": "24054457" + "$serde_json::private::Number": "23993702" daysToThreshold: - "$serde_json::private::Number": "-24054277" + "$serde_json::private::Number": "-23993522" dormancyStatus: dormant dormancyThreshold: "$serde_json::private::Number": "180" @@ -57,7 +57,7 @@ trace: "$serde_json::private::Number": "0" reference_map: daysToThreshold: - "$serde_json::private::Number": "-24054277" + "$serde_json::private::Number": "-23993522" rule: _id: r1-1 "daysToThreshold[i1-1]": "< 0" @@ -74,9 +74,9 @@ trace: customerPhone: "+15551234567" customerTier: premium daysSinceLastActivity: - "$serde_json::private::Number": "24054457" + "$serde_json::private::Number": "23993702" daysToThreshold: - "$serde_json::private::Number": "-24054277" + "$serde_json::private::Number": "-23993522" dormancyStatus: dormant dormancyThreshold: "$serde_json::private::Number": "180" @@ -131,9 +131,9 @@ trace: customerPhone: "+15551234567" customerTier: premium daysSinceLastActivity: - "$serde_json::private::Number": "24054457" + "$serde_json::private::Number": "23993702" daysToThreshold: - "$serde_json::private::Number": "-24054277" + "$serde_json::private::Number": "-23993522" dormancyThreshold: "$serde_json::private::Number": "180" lastActivityDate: 2024-11-15 @@ -142,9 +142,11 @@ trace: performance: "[perf]" traceData: daysSinceLastActivity: - result: "24054457" + result: + "$serde_json::private::Number": "23993702" daysToThreshold: - result: "-24054277" + result: + "$serde_json::private::Number": "-23993522" ip1: id: ip1 input: ~ @@ -181,9 +183,9 @@ trace: customerPhone: "+15551234567" customerTier: premium daysSinceLastActivity: - "$serde_json::private::Number": "24054457" + "$serde_json::private::Number": "23993702" daysToThreshold: - "$serde_json::private::Number": "-24054277" + "$serde_json::private::Number": "-23993522" dormancyStatus: dormant dormancyThreshold: "$serde_json::private::Number": "180" @@ -204,9 +206,9 @@ trace: customerPhone: "+15551234567" customerTier: premium daysSinceLastActivity: - "$serde_json::private::Number": "24054457" + "$serde_json::private::Number": "23993702" daysToThreshold: - "$serde_json::private::Number": "-24054277" + "$serde_json::private::Number": "-23993522" dormancyStatus: dormant dormancyThreshold: "$serde_json::private::Number": "180" diff --git a/core/engine/tests/snapshots/engine__affiliate-commission-calculator_0.snap b/core/engine/tests/snapshots/engine__affiliate-commission-calculator_0.snap index 50450b2c..5748d05b 100644 --- a/core/engine/tests/snapshots/engine__affiliate-commission-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__affiliate-commission-calculator_0.snap @@ -127,11 +127,14 @@ trace: performance: "[perf]" traceData: commissionAmount: - result: "69.3" + result: + "$serde_json::private::Number": "69.3" finalCommissionRate: - result: "0.198" + result: + "$serde_json::private::Number": "0.198" promotionMultiplier: - result: "1.25" + result: + "$serde_json::private::Number": "1.25" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__airline-loyalty-points-calculations_0.snap b/core/engine/tests/snapshots/engine__airline-loyalty-points-calculations_0.snap index 25c37299..ce8e5dbb 100644 --- a/core/engine/tests/snapshots/engine__airline-loyalty-points-calculations_0.snap +++ b/core/engine/tests/snapshots/engine__airline-loyalty-points-calculations_0.snap @@ -185,11 +185,14 @@ trace: performance: "[perf]" traceData: calculatedPoints: - result: "9000" + result: + "$serde_json::private::Number": "9000" seasonalPromotion: - result: "1.5" + result: + "$serde_json::private::Number": "1.5" totalPoints: - result: "9000" + result: + "$serde_json::private::Number": "9000" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__airline-upgrade-eligibility_0.snap b/core/engine/tests/snapshots/engine__airline-upgrade-eligibility_0.snap index d558cf80..59495f4c 100644 --- a/core/engine/tests/snapshots/engine__airline-upgrade-eligibility_0.snap +++ b/core/engine/tests/snapshots/engine__airline-upgrade-eligibility_0.snap @@ -414,11 +414,14 @@ trace: performance: "[perf]" traceData: cabinMultiplier: - result: "1" + result: + "$serde_json::private::Number": "1" finalScore: - result: "80" + result: + "$serde_json::private::Number": "80" totalScore: - result: "80" + result: + "$serde_json::private::Number": "80" input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__application-risk-assessment_0.snap b/core/engine/tests/snapshots/engine__application-risk-assessment_0.snap index 6e83a8d5..18672cb3 100644 --- a/core/engine/tests/snapshots/engine__application-risk-assessment_0.snap +++ b/core/engine/tests/snapshots/engine__application-risk-assessment_0.snap @@ -95,11 +95,13 @@ trace: performance: "[perf]" traceData: negativeFactors: - result: "[]" + result: [] negativeFactorsCount: - result: "0" + result: + "$serde_json::private::Number": "0" totalRiskScore: - result: "55" + result: + "$serde_json::private::Number": "55" classifyRisk: id: classifyRisk input: @@ -257,11 +259,12 @@ trace: performance: "[perf]" traceData: approvalStatus: - result: "\"manual-review\"" + result: manual-review interestRateModifier: - result: "0" + result: + "$serde_json::private::Number": "0" riskCategory: - result: "\"medium\"" + result: medium scoreCreditHistory: id: scoreCreditHistory input: diff --git a/core/engine/tests/snapshots/engine__auto-insurance-premium-calculator_0.snap b/core/engine/tests/snapshots/engine__auto-insurance-premium-calculator_0.snap index 24a7b4f3..c475e86a 100644 --- a/core/engine/tests/snapshots/engine__auto-insurance-premium-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__auto-insurance-premium-calculator_0.snap @@ -319,11 +319,14 @@ trace: performance: "[perf]" traceData: basePremium: - result: "1650" + result: + "$serde_json::private::Number": "1650" basePremiumPerThousand: - result: "5.5" + result: + "$serde_json::private::Number": "5.5" coverageAmountInThousands: - result: "300" + result: + "$serde_json::private::Number": "300" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__booking-fraud-detection_0.snap b/core/engine/tests/snapshots/engine__booking-fraud-detection_0.snap index 86d6373d..23a3166f 100644 --- a/core/engine/tests/snapshots/engine__booking-fraud-detection_0.snap +++ b/core/engine/tests/snapshots/engine__booking-fraud-detection_0.snap @@ -244,9 +244,9 @@ trace: performance: "[perf]" traceData: flags.manual_review: - result: "true" + result: true flags.requires_verification: - result: "true" + result: true ex1: id: ex1 input: @@ -306,9 +306,12 @@ trace: performance: "[perf]" traceData: risk_factors: - result: "[\"Multiple rapid bookings\",\"High-value prepaid card transaction\"]" + result: + - Multiple rapid bookings + - High-value prepaid card transaction total_risk_score: - result: "70" + result: + "$serde_json::private::Number": "70" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__booking-personalization-system_0.snap b/core/engine/tests/snapshots/engine__booking-personalization-system_0.snap index 7e40bec9..a61b40ce 100644 --- a/core/engine/tests/snapshots/engine__booking-personalization-system_0.snap +++ b/core/engine/tests/snapshots/engine__booking-personalization-system_0.snap @@ -210,11 +210,16 @@ trace: performance: "[perf]" traceData: allFeatures: - result: "[\"standardSearch\",\"standardNavigation\",\"joinLoyaltyBanner\",\"standardOptions\"]" + result: + - standardSearch + - standardNavigation + - joinLoyaltyBanner + - standardOptions bookingFlowTemplate: - result: "\"basic\"" + result: basic totalDiscountPercentage: - result: "0" + result: + "$serde_json::private::Number": "0" input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__care-team-assignment-system_0.snap b/core/engine/tests/snapshots/engine__care-team-assignment-system_0.snap index 2867900e..dcf8b987 100644 --- a/core/engine/tests/snapshots/engine__care-team-assignment-system_0.snap +++ b/core/engine/tests/snapshots/engine__care-team-assignment-system_0.snap @@ -474,19 +474,19 @@ trace: performance: "[perf]" traceData: availableProviders: - result: "null" + result: ~ facility: - result: "null" + result: ~ mobilityIssues: - result: "true" + result: true patient: - result: "null" + result: ~ requiresMentalHealthSupport: - result: "true" + result: true requiresNutritionSupport: - result: "true" + result: true requiresSpecialist: - result: "true" + result: true f1af25e2-126e-4882-8d35-6ae33dbc37bf: id: f1af25e2-126e-4882-8d35-6ae33dbc37bf input: diff --git a/core/engine/tests/snapshots/engine__cellular-data-rollover-system_0.snap b/core/engine/tests/snapshots/engine__cellular-data-rollover-system_0.snap index 8fd179cf..bcdc011e 100644 --- a/core/engine/tests/snapshots/engine__cellular-data-rollover-system_0.snap +++ b/core/engine/tests/snapshots/engine__cellular-data-rollover-system_0.snap @@ -108,11 +108,13 @@ trace: performance: "[perf]" traceData: isPositiveUnusedData: - result: "true" + result: true previousRolloverAmount: - result: "5" + result: + "$serde_json::private::Number": "5" unusedData: - result: "15" + result: + "$serde_json::private::Number": "15" ex2: id: ex2 input: @@ -149,11 +151,12 @@ trace: performance: "[perf]" traceData: nextBillingCycle.consecutiveRollovers: - result: "2" + result: + "$serde_json::private::Number": "2" nextBillingCycle.status: - result: "\"approved\"" + result: approved responseMessage: - result: "\"Rollover successful. You have 20 GB of rollover data available for your next billing cycle.\"" + result: Rollover successful. You have 20 GB of rollover data available for your next billing cycle. ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__claim-validation-system_0.snap b/core/engine/tests/snapshots/engine__claim-validation-system_0.snap index 441ce3a1..4bbccd76 100644 --- a/core/engine/tests/snapshots/engine__claim-validation-system_0.snap +++ b/core/engine/tests/snapshots/engine__claim-validation-system_0.snap @@ -115,11 +115,11 @@ trace: performance: "[perf]" traceData: isValid: - result: "false" + result: false nextStep: - result: "\"rejection\"" + result: rejection validationMessage: - result: "\"Claim reported more than 60 days after incident\"" + result: Claim reported more than 60 days after incident evaluateTimeframes: id: evaluateTimeframes input: diff --git a/core/engine/tests/snapshots/engine__clinical-pathway-selection_0.snap b/core/engine/tests/snapshots/engine__clinical-pathway-selection_0.snap index 4aee4a7c..49260885 100644 --- a/core/engine/tests/snapshots/engine__clinical-pathway-selection_0.snap +++ b/core/engine/tests/snapshots/engine__clinical-pathway-selection_0.snap @@ -125,13 +125,16 @@ trace: performance: "[perf]" traceData: comorbidityCount: - result: "3" + result: + "$serde_json::private::Number": "3" comorbidityRiskScore: - result: "9" + result: + "$serde_json::private::Number": "9" hasHighRiskComorbidity: - result: "true" + result: true totalRiskScore: - result: "17" + result: + "$serde_json::private::Number": "17" diagnoseTable: id: diagnoseTable input: @@ -498,11 +501,15 @@ trace: performance: "[perf]" traceData: followupFrequency: - result: "\"daily\"" + result: daily recommendedMonitoring: - result: "[\"comprehensive_vitals\",\"medication_adherence\",\"lifestyle_factors\",\"specialist_consultation\"]" + result: + - comprehensive_vitals + - medication_adherence + - lifestyle_factors + - specialist_consultation selectedPathway: - result: "\"intensive\"" + result: intensive patientFactorsTable: id: patientFactorsTable input: diff --git a/core/engine/tests/snapshots/engine__clinical-treatment-protocol_0.snap b/core/engine/tests/snapshots/engine__clinical-treatment-protocol_0.snap index f001eeb9..527607e6 100644 --- a/core/engine/tests/snapshots/engine__clinical-treatment-protocol_0.snap +++ b/core/engine/tests/snapshots/engine__clinical-treatment-protocol_0.snap @@ -292,6 +292,13 @@ trace: performance: "[perf]" traceData: protocol_name: - result: "\"oral_medication_moderate\"" + result: oral_medication_moderate treatment_protocol: - result: "{\"follow_up_frequency\":\"bi-weekly\",\"risk_adjustment\":\"modified_treatment\",\"base_treatment\":\"oral_medication\",\"protocol_intensity\":\"intensive\",\"dosage_instruction\":\"standard_elderly\",\"protocol_id\":\"oral_medication_moderate_intensive\",\"severity_level\":\"moderate_diabetes\"}" + result: + base_treatment: oral_medication + dosage_instruction: standard_elderly + follow_up_frequency: bi-weekly + protocol_id: oral_medication_moderate_intensive + protocol_intensity: intensive + risk_adjustment: modified_treatment + severity_level: moderate_diabetes diff --git a/core/engine/tests/snapshots/engine__clinical-trial-eligibility-screener_0.snap b/core/engine/tests/snapshots/engine__clinical-trial-eligibility-screener_0.snap deleted file mode 100644 index 465d70f5..00000000 --- a/core/engine/tests/snapshots/engine__clinical-trial-eligibility-screener_0.snap +++ /dev/null @@ -1,569 +0,0 @@ ---- -source: core/engine/tests/engine.rs -expression: serialized_result ---- -performance: "[perf]" -result: - decisionSummary: Patient is not eligible for clinical trial - eligibilityReasons: - - flag: true - reason: Diagnosis matches trial criteria - - flag: false - reason: Excluded comorbidity present - - flag: false - reason: Too many prior treatments - - flag: false - reason: Patient taking excluded medications - - flag: false - reason: Stage IV patients excluded from trial - - flag: true - reason: Age within eligible range - failedCriteria: - - comorbidity - - priorTreatment - - medication - - stage - isEligible: false -trace: - ageEligibility: - id: ageEligibility - input: - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - name: ageEligibility - order: - "$serde_json::private::Number": "4" - output: - eligibility: - age: - flag: true - reason: Age within eligible range - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "1" - reference_map: - patient.age: - "$serde_json::private::Number": "68" - rule: - _id: rule2 - "patient.age[age]": "" - comorbidityEligibility: - id: comorbidityEligibility - input: - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - name: comorbidityEligibility - order: - "$serde_json::private::Number": "6" - output: - eligibility: - comorbidity: - flag: false - reason: Excluded comorbidity present - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "0" - reference_map: - "patient.comorbidities ?? []": - - autoimmune_disease - - COPD - rule: - _id: rule1 - "patient.comorbidities ?? [][comorbidities]": "some($, # in ['autoimmune_disease', 'heart_failure', 'uncontrolled_diabetes'])" - diagnosisEligibility: - id: diagnosisEligibility - input: - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - name: diagnosisEligibility - order: - "$serde_json::private::Number": "1" - output: - eligibility: - diagnosis: - flag: true - reason: Diagnosis matches trial criteria - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "0" - reference_map: - patient.diagnosis: lung_cancer - rule: - _id: rule1 - "patient.diagnosis[diagnosis]": "'breast_cancer', 'lung_cancer', 'colorectal_cancer'" - diseaseStageEligibility: - id: diseaseStageEligibility - input: - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - name: diseaseStageEligibility - order: - "$serde_json::private::Number": "2" - output: - eligibility: - stage: - flag: false - reason: Stage IV patients excluded from trial - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "1" - reference_map: - patient.diseaseStage: IV - rule: - _id: rule2 - "patient.diseaseStage[stage]": "'IV'" - eligibilitySummary: - id: eligibilitySummary - input: - eligibility: - age: - flag: true - reason: Age within eligible range - comorbidity: - flag: false - reason: Excluded comorbidity present - diagnosis: - flag: true - reason: Diagnosis matches trial criteria - medication: - flag: false - reason: Patient taking excluded medications - priorTreatment: - flag: false - reason: Too many prior treatments - stage: - flag: false - reason: Stage IV patients excluded from trial - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - name: eligibilitySummary - order: - "$serde_json::private::Number": "7" - output: - decisionSummary: Patient is not eligible for clinical trial - eligibilityReasons: - - flag: true - reason: Diagnosis matches trial criteria - - flag: false - reason: Excluded comorbidity present - - flag: false - reason: Too many prior treatments - - flag: false - reason: Patient taking excluded medications - - flag: false - reason: Stage IV patients excluded from trial - - flag: true - reason: Age within eligible range - failedCriteria: - - comorbidity - - priorTreatment - - medication - - stage - isEligible: false - performance: "[perf]" - traceData: - decisionSummary: - result: "\"Patient is not eligible for clinical trial\"" - eligibilityReasons: - result: "[{\"reason\":\"Diagnosis matches trial criteria\",\"flag\":true},{\"reason\":\"Excluded comorbidity present\",\"flag\":false},{\"flag\":false,\"reason\":\"Too many prior treatments\"},{\"flag\":false,\"reason\":\"Patient taking excluded medications\"},{\"reason\":\"Stage IV patients excluded from trial\",\"flag\":false},{\"reason\":\"Age within eligible range\",\"flag\":true}]" - failedCriteria: - result: "[\"comorbidity\",\"priorTreatment\",\"medication\",\"stage\"]" - isEligible: - result: "false" - inputNode: - id: inputNode - input: ~ - name: patient - order: - "$serde_json::private::Number": "0" - output: - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - performance: "[perf]" - traceData: ~ - medicationEligibility: - id: medicationEligibility - input: - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - name: medicationEligibility - order: - "$serde_json::private::Number": "3" - output: - eligibility: - medication: - flag: false - reason: Patient taking excluded medications - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "0" - reference_map: - "patient.currentMedications ?? []": - - immunosuppressants - - albuterol - - omeprazole - rule: - _id: rule1 - "patient.currentMedications ?? [][medications]": "some($, # in ['immunosuppressants', 'anticancer_agents', 'corticosteroids'])" - priorTreatmentEligibility: - id: priorTreatmentEligibility - input: - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - name: priorTreatmentEligibility - order: - "$serde_json::private::Number": "5" - output: - eligibility: - priorTreatment: - flag: false - reason: Too many prior treatments - patient: - age: - "$serde_json::private::Number": "68" - comorbidities: - - autoimmune_disease - - COPD - currentMedications: - - immunosuppressants - - albuterol - - omeprazole - diagnosis: lung_cancer - diseaseStage: IV - id: P67890 - lastLabResults: - creatinine: - "$serde_json::private::Number": "1.2" - hgb: - "$serde_json::private::Number": "10.9" - plt: - "$serde_json::private::Number": "150" - wbc: - "$serde_json::private::Number": "3.8" - name: John Smith - priorTreatments: - "$serde_json::private::Number": "3" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "0" - reference_map: - patient.priorTreatments: - "$serde_json::private::Number": "3" - rule: - _id: rule1 - "patient.priorTreatments[priorTreatments]": "> 2" diff --git a/core/engine/tests/snapshots/engine__credit-limit-adjustment_0.snap b/core/engine/tests/snapshots/engine__credit-limit-adjustment_0.snap index bc61d52e..5def6fc4 100644 --- a/core/engine/tests/snapshots/engine__credit-limit-adjustment_0.snap +++ b/core/engine/tests/snapshots/engine__credit-limit-adjustment_0.snap @@ -161,9 +161,11 @@ trace: performance: "[perf]" traceData: recommendation.amount_change: - result: "1500" + result: + "$serde_json::private::Number": "1500" recommendation.new_credit_limit: - result: "6500" + result: + "$serde_json::private::Number": "6500" financialBehaviorNode: id: financialBehaviorNode input: @@ -443,7 +445,8 @@ trace: performance: "[perf]" traceData: total_adjustment_score: - result: "80" + result: + "$serde_json::private::Number": "80" utilizationNode: id: utilizationNode input: diff --git a/core/engine/tests/snapshots/engine__customer-eligibility-engine_0.snap b/core/engine/tests/snapshots/engine__customer-eligibility-engine_0.snap index 3fd24eeb..948b7e99 100644 --- a/core/engine/tests/snapshots/engine__customer-eligibility-engine_0.snap +++ b/core/engine/tests/snapshots/engine__customer-eligibility-engine_0.snap @@ -374,9 +374,15 @@ trace: performance: "[perf]" traceData: eligibility.offerCount: - result: "5" + result: + "$serde_json::private::Number": "5" eligibility.specialOffers: - result: "{\"dataBooster\":true,\"deviceUpgrade\":true,\"internationalBundle\":true,\"familyPlan\":true,\"loyaltyReward\":true}" + result: + dataBooster: true + deviceUpgrade: true + familyPlan: true + internationalBundle: true + loyaltyReward: true upgradeEligibility: id: upgradeEligibility input: diff --git a/core/engine/tests/snapshots/engine__customer-lifetime-value_0.snap b/core/engine/tests/snapshots/engine__customer-lifetime-value_0.snap index c6cdc89e..aa61ec7e 100644 --- a/core/engine/tests/snapshots/engine__customer-lifetime-value_0.snap +++ b/core/engine/tests/snapshots/engine__customer-lifetime-value_0.snap @@ -194,19 +194,26 @@ trace: performance: "[perf]" traceData: acquisitionCostRatio: - result: "0.0095436036647438072616219885" + result: + "$serde_json::private::Number": "0.0095436036647438072616219885" adjustedLTV: - result: "15567.333333333333333333333334" + result: + "$serde_json::private::Number": "15567.333333333333333333333334" averageOrderValue: - result: "168.4" + result: + "$serde_json::private::Number": "168.4" basicLTV: - result: "15717.333333333333333333333334" + result: + "$serde_json::private::Number": "15717.333333333333333333333334" customerLifetimeMonths: - result: "80" + result: + "$serde_json::private::Number": "80" grossMargin: - result: "0.35" + result: + "$serde_json::private::Number": "0.35" purchaseFrequency: - result: "3.3333333333333333333333333336" + result: + "$serde_json::private::Number": "3.3333333333333333333333333336" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__customer-onboarding-kyc-verification_0.snap b/core/engine/tests/snapshots/engine__customer-onboarding-kyc-verification_0.snap index 7ba278c7..8f9ba29f 100644 --- a/core/engine/tests/snapshots/engine__customer-onboarding-kyc-verification_0.snap +++ b/core/engine/tests/snapshots/engine__customer-onboarding-kyc-verification_0.snap @@ -419,11 +419,11 @@ trace: performance: "[perf]" traceData: dueDiligenceLevel: - result: "\"standard\"" + result: standard isSanctioned: - result: "false" + result: false requiresEDD: - result: "false" + result: false input: id: input input: ~ @@ -536,13 +536,18 @@ trace: performance: "[perf]" traceData: nextSteps: - result: "\"Onboarding approved\"" + result: Onboarding approved requiredActionsCount: - result: "0" + result: + "$serde_json::private::Number": "0" requirements: - result: "{\"sourceOfFunds\":false,\"enhancedMonitoring\":false,\"faceVerification\":false,\"addressVerification\":false}" + result: + addressVerification: false + enhancedMonitoring: false + faceVerification: false + sourceOfFunds: false verificationStatus: - result: "\"approved\"" + result: approved watchlistCheck: id: watchlistCheck input: diff --git a/core/engine/tests/snapshots/engine__delivery-route-optimizer_0.snap b/core/engine/tests/snapshots/engine__delivery-route-optimizer_0.snap index b5b27586..e0917efb 100644 --- a/core/engine/tests/snapshots/engine__delivery-route-optimizer_0.snap +++ b/core/engine/tests/snapshots/engine__delivery-route-optimizer_0.snap @@ -194,11 +194,14 @@ trace: performance: "[perf]" traceData: distanceScore: - result: "30" + result: + "$serde_json::private::Number": "30" timeWindowScore: - result: "30" + result: + "$serde_json::private::Number": "30" totalScore: - result: "160" + result: + "$serde_json::private::Number": "160" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__device-compatibility-checker_0.snap b/core/engine/tests/snapshots/engine__device-compatibility-checker_0.snap index 2fa1dbf3..cc259a2a 100644 --- a/core/engine/tests/snapshots/engine__device-compatibility-checker_0.snap +++ b/core/engine/tests/snapshots/engine__device-compatibility-checker_0.snap @@ -126,9 +126,10 @@ trace: performance: "[perf]" traceData: majorVersion: - result: "14" + result: + "$serde_json::private::Number": "14" normalizedModel: - result: "\"iphone 13 pro\"" + result: iphone 13 pro ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__disaster-relief-fund-allocation_0.snap b/core/engine/tests/snapshots/engine__disaster-relief-fund-allocation_0.snap index cfac0c44..ff194675 100644 --- a/core/engine/tests/snapshots/engine__disaster-relief-fund-allocation_0.snap +++ b/core/engine/tests/snapshots/engine__disaster-relief-fund-allocation_0.snap @@ -301,9 +301,11 @@ trace: performance: "[perf]" traceData: householdMultiplier: - result: "1.6" + result: + "$serde_json::private::Number": "1.6" initialAllocation: - result: "14400" + result: + "$serde_json::private::Number": "14400" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__dynamic-marketplace-comission-calculator_0.snap b/core/engine/tests/snapshots/engine__dynamic-marketplace-comission-calculator_0.snap index 5bc71e58..195f6180 100644 --- a/core/engine/tests/snapshots/engine__dynamic-marketplace-comission-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__dynamic-marketplace-comission-calculator_0.snap @@ -133,13 +133,16 @@ trace: performance: "[perf]" traceData: finalCommissionRate: - result: "0.168" + result: + "$serde_json::private::Number": "0.168" isPromotionActive: - result: "false" + result: false promotionAdjustment: - result: "0" + result: + "$serde_json::private::Number": "0" volumeMultiplier: - result: "1.2" + result: + "$serde_json::private::Number": "1.2" sellerPerformance: id: sellerPerformance input: diff --git a/core/engine/tests/snapshots/engine__dynamic-shipping-cost-calculator_0.snap b/core/engine/tests/snapshots/engine__dynamic-shipping-cost-calculator_0.snap index c0d4b10b..a19b81e8 100644 --- a/core/engine/tests/snapshots/engine__dynamic-shipping-cost-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__dynamic-shipping-cost-calculator_0.snap @@ -177,7 +177,7 @@ trace: "$serde_json::private::Number": "2" reference_map: "dayOfYear('now')": - "$serde_json::private::Number": "232" + "$serde_json::private::Number": "231" rule: _id: r3-3 "dayOfYear('now')[i3-1]": "> 172 and < 265" @@ -227,11 +227,14 @@ trace: performance: "[perf]" traceData: dimensionalWeight: - result: "4.8" + result: + "$serde_json::private::Number": "4.8" distanceFactor: - result: "2.5" + result: + "$serde_json::private::Number": "2.5" effectiveWeight: - result: "25" + result: + "$serde_json::private::Number": "25" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__dynamic-tarrif-engine_0.snap b/core/engine/tests/snapshots/engine__dynamic-tarrif-engine_0.snap index 6af60715..0803545f 100644 --- a/core/engine/tests/snapshots/engine__dynamic-tarrif-engine_0.snap +++ b/core/engine/tests/snapshots/engine__dynamic-tarrif-engine_0.snap @@ -50,13 +50,18 @@ trace: performance: "[perf]" traceData: baseTariff: - result: "0.05" + result: + "$serde_json::private::Number": "0.05" currency: - result: "\"EUR\"" + result: EUR finalTariff: - result: "0.048" + result: + "$serde_json::private::Number": "0.048" rulesSummary: - result: "[\"Base rate: 0.05 per unit\",\"Premium user call discount\",\"Peak hour domestic rate\"]" + result: + - "Base rate: 0.05 per unit" + - Premium user call discount + - Peak hour domestic rate input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__dynamic-ticket-pricing_0.snap b/core/engine/tests/snapshots/engine__dynamic-ticket-pricing_0.snap index 6d1ed0e8..256de1f1 100644 --- a/core/engine/tests/snapshots/engine__dynamic-ticket-pricing_0.snap +++ b/core/engine/tests/snapshots/engine__dynamic-ticket-pricing_0.snap @@ -225,11 +225,14 @@ trace: performance: "[perf]" traceData: availabilityRatio: - result: "0.0277777777777777777777777778" + result: + "$serde_json::private::Number": "0.0277777777777777777777777778" competitiveIndex: - result: "0.1" + result: + "$serde_json::private::Number": "0.1" demandIndex: - result: "0.95" + result: + "$serde_json::private::Number": "0.95" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__environment-compliance-assessment_0.snap b/core/engine/tests/snapshots/engine__environment-compliance-assessment_0.snap index 80f61181..233b7f7f 100644 --- a/core/engine/tests/snapshots/engine__environment-compliance-assessment_0.snap +++ b/core/engine/tests/snapshots/engine__environment-compliance-assessment_0.snap @@ -282,15 +282,17 @@ trace: performance: "[perf]" traceData: carbonIntensity: - result: "185" + result: + "$serde_json::private::Number": "185" exceededThreshold: - result: "true" + result: true hasWasteViolations: - result: "true" + result: true hasWaterViolations: - result: "false" + result: false percentOverThreshold: - result: "23.33333333333333333333333333" + result: + "$serde_json::private::Number": "23.33333333333333333333333333" industryRiskTable: id: industryRiskTable input: diff --git a/core/engine/tests/snapshots/engine__expression-default_0.snap b/core/engine/tests/snapshots/engine__expression-default_0.snap index abbc07d8..69c1770e 100644 --- a/core/engine/tests/snapshots/engine__expression-default_0.snap +++ b/core/engine/tests/snapshots/engine__expression-default_0.snap @@ -24,7 +24,8 @@ trace: performance: "[perf]" traceData: sum: - result: "3" + result: + "$serde_json::private::Number": "3" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-default_1.snap b/core/engine/tests/snapshots/engine__expression-default_1.snap index 53740f31..f2f714ec 100644 --- a/core/engine/tests/snapshots/engine__expression-default_1.snap +++ b/core/engine/tests/snapshots/engine__expression-default_1.snap @@ -25,7 +25,8 @@ trace: performance: "[perf]" traceData: sum: - result: "8" + result: + "$serde_json::private::Number": "8" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-default_2.snap b/core/engine/tests/snapshots/engine__expression-default_2.snap index 7d611a11..51489494 100644 --- a/core/engine/tests/snapshots/engine__expression-default_2.snap +++ b/core/engine/tests/snapshots/engine__expression-default_2.snap @@ -27,7 +27,8 @@ trace: performance: "[perf]" traceData: sum: - result: "30" + result: + "$serde_json::private::Number": "30" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-default_3.snap b/core/engine/tests/snapshots/engine__expression-default_3.snap index 707be199..fae19f6f 100644 --- a/core/engine/tests/snapshots/engine__expression-default_3.snap +++ b/core/engine/tests/snapshots/engine__expression-default_3.snap @@ -24,7 +24,8 @@ trace: performance: "[perf]" traceData: sum: - result: "10" + result: + "$serde_json::private::Number": "10" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-default_4.snap b/core/engine/tests/snapshots/engine__expression-default_4.snap index 6886c512..1fa99b67 100644 --- a/core/engine/tests/snapshots/engine__expression-default_4.snap +++ b/core/engine/tests/snapshots/engine__expression-default_4.snap @@ -5,13 +5,13 @@ expression: serialized_result performance: "[perf]" result: sum: - "$serde_json::private::Number": "1" + "$serde_json::private::Number": "0" trace: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770: id: 6b9cfc7e-4776-4b3f-8a19-c2a4d7874770 input: a: - "$serde_json::private::Number": "-4" + "$serde_json::private::Number": "-5" b: "$serde_json::private::Number": "5" negative: true @@ -20,11 +20,12 @@ trace: "$serde_json::private::Number": "1" output: sum: - "$serde_json::private::Number": "1" + "$serde_json::private::Number": "0" performance: "[perf]" traceData: sum: - result: "1" + result: + "$serde_json::private::Number": "0" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ @@ -33,7 +34,7 @@ trace: "$serde_json::private::Number": "0" output: a: - "$serde_json::private::Number": "-4" + "$serde_json::private::Number": "-5" b: "$serde_json::private::Number": "5" negative: true diff --git a/core/engine/tests/snapshots/engine__expression-fields_0.snap b/core/engine/tests/snapshots/engine__expression-fields_0.snap index 349a1972..2beb401a 100644 --- a/core/engine/tests/snapshots/engine__expression-fields_0.snap +++ b/core/engine/tests/snapshots/engine__expression-fields_0.snap @@ -44,7 +44,7 @@ trace: performance: "[perf]" traceData: fullName: - result: "\"John Doe\"" + result: John Doe input-node: id: input-node input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-fields_1.snap b/core/engine/tests/snapshots/engine__expression-fields_1.snap index 9612f989..54e3252c 100644 --- a/core/engine/tests/snapshots/engine__expression-fields_1.snap +++ b/core/engine/tests/snapshots/engine__expression-fields_1.snap @@ -44,7 +44,7 @@ trace: performance: "[perf]" traceData: fullName: - result: "\"Jane Smith\"" + result: Jane Smith input-node: id: input-node input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-loop_0.snap b/core/engine/tests/snapshots/engine__expression-loop_0.snap index 0dd840f7..454f5ac8 100644 --- a/core/engine/tests/snapshots/engine__expression-loop_0.snap +++ b/core/engine/tests/snapshots/engine__expression-loop_0.snap @@ -81,11 +81,14 @@ trace: performance: "[perf]" traceData: - totalPrice: - result: "1.5" + result: + "$serde_json::private::Number": "1.5" - totalPrice: - result: "1.5" + result: + "$serde_json::private::Number": "1.5" - totalPrice: - result: "1.4" + result: + "$serde_json::private::Number": "1.4" input-node: id: input-node input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_0.snap b/core/engine/tests/snapshots/engine__expression-passthrough_0.snap index 94c78cb3..8828f971 100644 --- a/core/engine/tests/snapshots/engine__expression-passthrough_0.snap +++ b/core/engine/tests/snapshots/engine__expression-passthrough_0.snap @@ -32,7 +32,8 @@ trace: performance: "[perf]" traceData: sum: - result: "3" + result: + "$serde_json::private::Number": "3" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_1.snap b/core/engine/tests/snapshots/engine__expression-passthrough_1.snap index e2e91185..b97f4eda 100644 --- a/core/engine/tests/snapshots/engine__expression-passthrough_1.snap +++ b/core/engine/tests/snapshots/engine__expression-passthrough_1.snap @@ -33,7 +33,8 @@ trace: performance: "[perf]" traceData: sum: - result: "8" + result: + "$serde_json::private::Number": "8" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_2.snap b/core/engine/tests/snapshots/engine__expression-passthrough_2.snap index 841a38ec..00218b34 100644 --- a/core/engine/tests/snapshots/engine__expression-passthrough_2.snap +++ b/core/engine/tests/snapshots/engine__expression-passthrough_2.snap @@ -34,7 +34,8 @@ trace: performance: "[perf]" traceData: sum: - result: "30" + result: + "$serde_json::private::Number": "30" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_3.snap b/core/engine/tests/snapshots/engine__expression-passthrough_3.snap index a5012336..b4b2848c 100644 --- a/core/engine/tests/snapshots/engine__expression-passthrough_3.snap +++ b/core/engine/tests/snapshots/engine__expression-passthrough_3.snap @@ -35,7 +35,8 @@ trace: performance: "[perf]" traceData: sum: - result: "10" + result: + "$serde_json::private::Number": "10" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-passthrough_4.snap b/core/engine/tests/snapshots/engine__expression-passthrough_4.snap index 49ec48e9..81efffe7 100644 --- a/core/engine/tests/snapshots/engine__expression-passthrough_4.snap +++ b/core/engine/tests/snapshots/engine__expression-passthrough_4.snap @@ -43,7 +43,8 @@ trace: performance: "[perf]" traceData: sum: - result: "2" + result: + "$serde_json::private::Number": "2" deced339-bace-452a-8db0-777f038bffe8: id: deced339-bace-452a-8db0-777f038bffe8 input: ~ diff --git a/core/engine/tests/snapshots/engine__expression-table-map_0.snap b/core/engine/tests/snapshots/engine__expression-table-map_0.snap index 56ccf031..658198cd 100644 --- a/core/engine/tests/snapshots/engine__expression-table-map_0.snap +++ b/core/engine/tests/snapshots/engine__expression-table-map_0.snap @@ -89,7 +89,8 @@ trace: performance: "[perf]" traceData: exprItemsSum: - result: "50" + result: + "$serde_json::private::Number": "50" 5f56e61b-5687-4758-8524-8121df13b2ba: id: 5f56e61b-5687-4758-8524-8121df13b2ba input: @@ -131,7 +132,8 @@ trace: performance: "[perf]" traceData: - discount: - result: "5" + result: + "$serde_json::private::Number": "5" 8ceca45e-e6ff-4613-984c-5846e53c5a39: id: 8ceca45e-e6ff-4613-984c-5846e53c5a39 input: @@ -190,7 +192,8 @@ trace: performance: "[perf]" traceData: tblItemsSum: - result: "1050" + result: + "$serde_json::private::Number": "1050" b8ebb212-e290-4131-9703-0bb7b1fd2328: id: b8ebb212-e290-4131-9703-0bb7b1fd2328 input: diff --git a/core/engine/tests/snapshots/engine__expression-table-map_1.snap b/core/engine/tests/snapshots/engine__expression-table-map_1.snap index 897216d2..bf5b8db7 100644 --- a/core/engine/tests/snapshots/engine__expression-table-map_1.snap +++ b/core/engine/tests/snapshots/engine__expression-table-map_1.snap @@ -69,7 +69,8 @@ trace: performance: "[perf]" traceData: exprItemsSum: - result: "0" + result: + "$serde_json::private::Number": "0" 5f56e61b-5687-4758-8524-8121df13b2ba: id: 5f56e61b-5687-4758-8524-8121df13b2ba input: @@ -158,7 +159,8 @@ trace: performance: "[perf]" traceData: tblItemsSum: - result: "1050" + result: + "$serde_json::private::Number": "1050" b8ebb212-e290-4131-9703-0bb7b1fd2328: id: b8ebb212-e290-4131-9703-0bb7b1fd2328 input: diff --git a/core/engine/tests/snapshots/engine__expression-table-map_2.snap b/core/engine/tests/snapshots/engine__expression-table-map_2.snap index 619240c2..46fd9da7 100644 --- a/core/engine/tests/snapshots/engine__expression-table-map_2.snap +++ b/core/engine/tests/snapshots/engine__expression-table-map_2.snap @@ -89,7 +89,8 @@ trace: performance: "[perf]" traceData: exprItemsSum: - result: "51" + result: + "$serde_json::private::Number": "51" 5f56e61b-5687-4758-8524-8121df13b2ba: id: 5f56e61b-5687-4758-8524-8121df13b2ba input: @@ -131,7 +132,8 @@ trace: performance: "[perf]" traceData: - discount: - result: "5" + result: + "$serde_json::private::Number": "5" 8ceca45e-e6ff-4613-984c-5846e53c5a39: id: 8ceca45e-e6ff-4613-984c-5846e53c5a39 input: @@ -190,7 +192,8 @@ trace: performance: "[perf]" traceData: tblItemsSum: - result: "1051" + result: + "$serde_json::private::Number": "1051" b8ebb212-e290-4131-9703-0bb7b1fd2328: id: b8ebb212-e290-4131-9703-0bb7b1fd2328 input: diff --git a/core/engine/tests/snapshots/engine__flash-sale-eligibility_0.snap b/core/engine/tests/snapshots/engine__flash-sale-eligibility_0.snap index 8bfa5c1a..249e7ba3 100644 --- a/core/engine/tests/snapshots/engine__flash-sale-eligibility_0.snap +++ b/core/engine/tests/snapshots/engine__flash-sale-eligibility_0.snap @@ -179,11 +179,13 @@ trace: performance: "[perf]" traceData: isQualifiedSeller: - result: "true" + result: true seasonalityFactor: - result: "1.2" + result: + "$serde_json::private::Number": "1.2" sellerFactor: - result: "1.5" + result: + "$serde_json::private::Number": "1.5" determineEligibility: id: determineEligibility input: diff --git a/core/engine/tests/snapshots/engine__flight-ancillary-recommendations_0.snap b/core/engine/tests/snapshots/engine__flight-ancillary-recommendations_0.snap deleted file mode 100644 index 6180fb02..00000000 --- a/core/engine/tests/snapshots/engine__flight-ancillary-recommendations_0.snap +++ /dev/null @@ -1,630 +0,0 @@ ---- -source: core/engine/tests/engine.rs -expression: serialized_result ---- -performance: "[perf]" -result: - recommendations: - - priority: - "$serde_json::private::Number": "5" - productType: lounge - - priority: - "$serde_json::private::Number": "4" - productType: priority_boarding - - priority: - "$serde_json::private::Number": "3" - productType: wifi - - priority: - "$serde_json::private::Number": "4" - productType: lounge - - priority: - "$serde_json::private::Number": "3" - productType: travel_insurance - - priority: - "$serde_json::private::Number": "2" - productType: premium_meal - - priority: - "$serde_json::private::Number": "4" - productType: fast_track_security -trace: - 8cb0ce16-c426-4988-b39f-d122499bc1fd: - id: 8cb0ce16-c426-4988-b39f-d122499bc1fd - input: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - flightDurationCategory: long - hasBoughtBaggage: false - hasBoughtLounge: false - hasBoughtMeals: false - hasBoughtSeats: true - isPremiumCustomer: true - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - recommendations: - additional: - - priority: - "$serde_json::private::Number": "4" - productType: lounge - - priority: - "$serde_json::private::Number": "3" - productType: travel_insurance - - priority: - "$serde_json::private::Number": "2" - productType: premium_meal - - priority: - "$serde_json::private::Number": "4" - productType: fast_track_security - base: - - priority: - "$serde_json::private::Number": "5" - productType: lounge - - priority: - "$serde_json::private::Number": "4" - productType: priority_boarding - - priority: - "$serde_json::private::Number": "3" - productType: wifi - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - name: join_recommendations - order: - "$serde_json::private::Number": "5" - output: - recommendations: - - priority: - "$serde_json::private::Number": "5" - productType: lounge - - priority: - "$serde_json::private::Number": "4" - productType: priority_boarding - - priority: - "$serde_json::private::Number": "3" - productType: wifi - - priority: - "$serde_json::private::Number": "4" - productType: lounge - - priority: - "$serde_json::private::Number": "3" - productType: travel_insurance - - priority: - "$serde_json::private::Number": "2" - productType: premium_meal - - priority: - "$serde_json::private::Number": "4" - productType: fast_track_security - performance: "[perf]" - traceData: - recommendations: - result: "[{\"productType\":\"lounge\",\"priority\":5},{\"productType\":\"priority_boarding\",\"priority\":4},{\"productType\":\"wifi\",\"priority\":3},{\"priority\":4,\"productType\":\"lounge\"},{\"productType\":\"travel_insurance\",\"priority\":3},{\"productType\":\"premium_meal\",\"priority\":2},{\"productType\":\"fast_track_security\",\"priority\":4}]" - dt1: - id: dt1 - input: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - name: categorize_flight_duration - order: - "$serde_json::private::Number": "1" - output: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - flightDurationCategory: long - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "0" - reference_map: - route.flightDurationMinutes: - "$serde_json::private::Number": "480" - rule: - _id: r1-1 - "route.flightDurationMinutes[i1-1]": ">= 240" - dt2: - id: dt2 - input: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - flightDurationCategory: long - hasBoughtBaggage: false - hasBoughtLounge: false - hasBoughtMeals: false - hasBoughtSeats: true - isPremiumCustomer: true - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - name: base_recommendations - order: - "$serde_json::private::Number": "3" - output: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - flightDurationCategory: long - hasBoughtBaggage: false - hasBoughtLounge: false - hasBoughtMeals: false - hasBoughtSeats: true - isPremiumCustomer: true - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - recommendations: - base: - - priority: - "$serde_json::private::Number": "5" - productType: lounge - - priority: - "$serde_json::private::Number": "4" - productType: priority_boarding - - priority: - "$serde_json::private::Number": "3" - productType: wifi - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - performance: "[perf]" - traceData: - - index: - "$serde_json::private::Number": "0" - reference_map: - flightDurationCategory: long - travelPurpose: business - rule: - _id: r2-1 - "flightDurationCategory[i2-2]": "'long'" - "travelPurpose[i2-1]": "'business'" - - index: - "$serde_json::private::Number": "1" - reference_map: - flightDurationCategory: long - travelPurpose: business - rule: - _id: r2-2 - "flightDurationCategory[i2-2]": "'medium', 'long'" - "travelPurpose[i2-1]": "'business'" - - index: - "$serde_json::private::Number": "2" - reference_map: - flightDurationCategory: long - travelPurpose: business - rule: - _id: r2-3 - "flightDurationCategory[i2-2]": "" - "travelPurpose[i2-1]": "'business'" - dt3: - id: dt3 - input: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - flightDurationCategory: long - hasBoughtBaggage: false - hasBoughtLounge: false - hasBoughtMeals: false - hasBoughtSeats: true - isPremiumCustomer: true - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - recommendations: - base: - - priority: - "$serde_json::private::Number": "5" - productType: lounge - - priority: - "$serde_json::private::Number": "4" - productType: priority_boarding - - priority: - "$serde_json::private::Number": "3" - productType: wifi - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - name: additional_recommendations - order: - "$serde_json::private::Number": "4" - output: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - flightDurationCategory: long - hasBoughtBaggage: false - hasBoughtLounge: false - hasBoughtMeals: false - hasBoughtSeats: true - isPremiumCustomer: true - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - recommendations: - additional: - - priority: - "$serde_json::private::Number": "4" - productType: lounge - - priority: - "$serde_json::private::Number": "3" - productType: travel_insurance - - priority: - "$serde_json::private::Number": "2" - productType: premium_meal - - priority: - "$serde_json::private::Number": "4" - productType: fast_track_security - base: - - priority: - "$serde_json::private::Number": "5" - productType: lounge - - priority: - "$serde_json::private::Number": "4" - productType: priority_boarding - - priority: - "$serde_json::private::Number": "3" - productType: wifi - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - performance: "[perf]" - traceData: - - index: - "$serde_json::private::Number": "0" - reference_map: {} - rule: - _id: r3-1 - - index: - "$serde_json::private::Number": "1" - reference_map: {} - rule: - _id: r3-2 - - index: - "$serde_json::private::Number": "2" - reference_map: {} - rule: - _id: r3-3 - - index: - "$serde_json::private::Number": "3" - reference_map: {} - rule: - _id: r3-4 - ex1: - id: ex1 - input: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - flightDurationCategory: long - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - name: calculate_customer_attributes - order: - "$serde_json::private::Number": "2" - output: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - flightDurationCategory: long - hasBoughtBaggage: false - hasBoughtLounge: false - hasBoughtMeals: false - hasBoughtSeats: true - isPremiumCustomer: true - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - performance: "[perf]" - traceData: - hasBoughtBaggage: - result: "false" - hasBoughtLounge: - result: "false" - hasBoughtMeals: - result: "false" - hasBoughtSeats: - result: "true" - isPremiumCustomer: - result: "true" - ip1: - id: ip1 - input: ~ - name: request - order: - "$serde_json::private::Number": "0" - output: - customerProfile: - id: cust-12345 - loyaltyTier: gold - preferredCurrency: USD - preferredLanguage: en - travelFrequency: frequent - previousPurchases: - - bookingId: bkg-9876 - productDetails: - amount: - "$serde_json::private::Number": "35" - seatType: extra_legroom - productType: seat - purchaseDate: "2024-12-10T14:22:00Z" - - bookingId: bkg-8765 - productDetails: - amount: - "$serde_json::private::Number": "19.99" - packageType: full_flight - productType: wifi - purchaseDate: "2024-11-05T09:15:00Z" - route: - departureTime: "2025-04-15T08:30:00Z" - destination: international - flightDurationMinutes: - "$serde_json::private::Number": "480" - hasAirportLounge: true - origin: JFK - returnTime: "2025-04-22T15:45:00Z" - travelPurpose: business - tripDetails: - cabinClass: economy - dateFlexibility: fixed - passengers: - "$serde_json::private::Number": "1" - performance: "[perf]" - traceData: ~ diff --git a/core/engine/tests/snapshots/engine__flight-dispatch-decision-system_0.snap b/core/engine/tests/snapshots/engine__flight-dispatch-decision-system_0.snap index e1ea9cf9..b9183c6e 100644 --- a/core/engine/tests/snapshots/engine__flight-dispatch-decision-system_0.snap +++ b/core/engine/tests/snapshots/engine__flight-dispatch-decision-system_0.snap @@ -338,13 +338,16 @@ trace: performance: "[perf]" traceData: dispatchReasons: - result: "[{\"flag\":false,\"reason\":\"Extreme wind and low visibility\"}]" + result: + - flag: false + reason: Extreme wind and low visibility dispatchSummary: - result: "\"Flight dispatch denied\"" + result: Flight dispatch denied failedCriteria: - result: "[\"weather\"]" + result: + - weather isDispatchable: - result: "false" + result: false inputNode: id: inputNode input: ~ @@ -622,13 +625,17 @@ trace: performance: "[perf]" traceData: estimatedTakeoffWeight: - result: "44850" + result: + "$serde_json::private::Number": "44850" passengerWeight: - result: "850" + result: + "$serde_json::private::Number": "850" totalCargo: - result: "2500" + result: + "$serde_json::private::Number": "2500" totalPassengers: - result: "10" + result: + "$serde_json::private::Number": "10" weightEligibility: id: weightEligibility input: diff --git a/core/engine/tests/snapshots/engine__flight-rebooking-fee-calculator_0.snap b/core/engine/tests/snapshots/engine__flight-rebooking-fee-calculator_0.snap index 01ebc5ec..9d01b5f2 100644 --- a/core/engine/tests/snapshots/engine__flight-rebooking-fee-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__flight-rebooking-fee-calculator_0.snap @@ -283,7 +283,8 @@ trace: performance: "[perf]" traceData: adjustedFee: - result: "188" + result: + "$serde_json::private::Number": "188" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__grant-funding-distribution_0.snap b/core/engine/tests/snapshots/engine__grant-funding-distribution_0.snap index 7daa2c8f..1d169e9f 100644 --- a/core/engine/tests/snapshots/engine__grant-funding-distribution_0.snap +++ b/core/engine/tests/snapshots/engine__grant-funding-distribution_0.snap @@ -154,13 +154,16 @@ trace: performance: "[perf]" traceData: fundingPercentage: - result: "76" + result: + "$serde_json::private::Number": "76" fundingStatus: - result: "\"Approved\"" + result: Approved grantAmount: - result: "57000" + result: + "$serde_json::private::Number": "57000" maxPossibleAmount: - result: "57000" + result: + "$serde_json::private::Number": "57000" inputNode: id: inputNode input: ~ diff --git a/core/engine/tests/snapshots/engine__import-duties-calculator_0.snap b/core/engine/tests/snapshots/engine__import-duties-calculator_0.snap index 4d7b2e3a..14ac3140 100644 --- a/core/engine/tests/snapshots/engine__import-duties-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__import-duties-calculator_0.snap @@ -122,19 +122,26 @@ trace: performance: "[perf]" traceData: additionalFees: - result: "0" + result: + "$serde_json::private::Number": "0" baseDuty: - result: "180" + result: + "$serde_json::private::Number": "180" countryAdjustment: - result: "225" + result: + "$serde_json::private::Number": "225" dutyRate: - result: "0.1875" + result: + "$serde_json::private::Number": "0.1875" minDuty: - result: "225" + result: + "$serde_json::private::Number": "225" preferentialDiscount: - result: "225" + result: + "$serde_json::private::Number": "225" totalDuty: - result: "225" + result: + "$serde_json::private::Number": "225" input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__insurance-agent-commission_0.snap b/core/engine/tests/snapshots/engine__insurance-agent-commission_0.snap index 1d8178ea..64bda297 100644 --- a/core/engine/tests/snapshots/engine__insurance-agent-commission_0.snap +++ b/core/engine/tests/snapshots/engine__insurance-agent-commission_0.snap @@ -106,7 +106,8 @@ trace: performance: "[perf]" traceData: baseCommission: - result: "360" + result: + "$serde_json::private::Number": "360" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__insurance-prior-authorization_0.snap b/core/engine/tests/snapshots/engine__insurance-prior-authorization_0.snap index b976042f..b61a8b06 100644 --- a/core/engine/tests/snapshots/engine__insurance-prior-authorization_0.snap +++ b/core/engine/tests/snapshots/engine__insurance-prior-authorization_0.snap @@ -7,7 +7,7 @@ result: reason: Advanced imaging requires prior authorization requiresAuthorization: true timestamp: - "$serde_json::private::Number": "1755682995" + "$serde_json::private::Number": "1755622502" trace: commercialRules: id: commercialRules @@ -116,15 +116,16 @@ trace: reason: Advanced imaging requires prior authorization requiresAuthorization: true timestamp: - "$serde_json::private::Number": "1755682995" + "$serde_json::private::Number": "1755622502" performance: "[perf]" traceData: reason: - result: "\"Advanced imaging requires prior authorization\"" + result: Advanced imaging requires prior authorization requiresAuthorization: - result: "true" + result: true timestamp: - result: "1755682995" + result: + "$serde_json::private::Number": "1755622502" inputNode: id: inputNode input: ~ diff --git a/core/engine/tests/snapshots/engine__insurance-underwriting-risk_0.snap b/core/engine/tests/snapshots/engine__insurance-underwriting-risk_0.snap index 6338d23b..335941a9 100644 --- a/core/engine/tests/snapshots/engine__insurance-underwriting-risk_0.snap +++ b/core/engine/tests/snapshots/engine__insurance-underwriting-risk_0.snap @@ -248,9 +248,12 @@ trace: performance: "[perf]" traceData: riskDescriptions: - result: "[\"High risk medical condition\",\"Multiple pre-existing conditions\"]" + result: + - High risk medical condition + - Multiple pre-existing conditions totalRiskScore: - result: "30" + result: + "$serde_json::private::Number": "30" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__international-roaming-policy-manager_0.snap b/core/engine/tests/snapshots/engine__international-roaming-policy-manager_0.snap index 4bce3907..81a48b53 100644 --- a/core/engine/tests/snapshots/engine__international-roaming-policy-manager_0.snap +++ b/core/engine/tests/snapshots/engine__international-roaming-policy-manager_0.snap @@ -139,13 +139,15 @@ trace: performance: "[perf]" traceData: isDataRoamingEnabled: - result: "true" + result: true isVoiceRoamingEnabled: - result: "true" + result: true remainingDataAllowance: - result: "3750" + result: + "$serde_json::private::Number": "3750" totalEstimatedDailyCost: - result: "252.75" + result: + "$serde_json::private::Number": "252.75" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__last-mile-delivery-assignment_0.snap b/core/engine/tests/snapshots/engine__last-mile-delivery-assignment_0.snap index 539487be..568ca842 100644 --- a/core/engine/tests/snapshots/engine__last-mile-delivery-assignment_0.snap +++ b/core/engine/tests/snapshots/engine__last-mile-delivery-assignment_0.snap @@ -9,7 +9,7 @@ result: "$serde_json::private::Number": "28" deliveryPersonId: DP-789 estimatedArrival: - "$serde_json::private::Number": "1755683930" + "$serde_json::private::Number": "1755623438" packageId: PKG-12345 assignmentStatus: assigned capacityFactor: @@ -263,15 +263,19 @@ trace: performance: "[perf]" traceData: capacityFactor: - result: "5" + result: + "$serde_json::private::Number": "5" distanceScore: - result: "7" + result: + "$serde_json::private::Number": "7" recommendedAssignment: - result: "true" + result: true slaFactor: - result: "6" + result: + "$serde_json::private::Number": "6" totalScore: - result: "28" + result: + "$serde_json::private::Number": "28" ex2: id: ex2 input: @@ -335,7 +339,7 @@ trace: "$serde_json::private::Number": "28" deliveryPersonId: DP-789 estimatedArrival: - "$serde_json::private::Number": "1755683930" + "$serde_json::private::Number": "1755623438" packageId: PKG-12345 assignmentStatus: assigned capacityFactor: @@ -393,11 +397,17 @@ trace: performance: "[perf]" traceData: assignmentDetails: - result: "{\"deliveryPersonId\":\"DP-789\",\"assignmentScore\":28,\"packageId\":\"PKG-12345\",\"estimatedArrival\":1755683930}" + result: + assignmentScore: + "$serde_json::private::Number": "28" + deliveryPersonId: DP-789 + estimatedArrival: + "$serde_json::private::Number": "1755623438" + packageId: PKG-12345 assignmentStatus: - result: "\"assigned\"" + result: assigned message: - result: "\"Package successfully assigned to delivery person\"" + result: Package successfully assigned to delivery person ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__legacy-plan-management_0.snap b/core/engine/tests/snapshots/engine__legacy-plan-management_0.snap index 28cc1a11..b3ee5419 100644 --- a/core/engine/tests/snapshots/engine__legacy-plan-management_0.snap +++ b/core/engine/tests/snapshots/engine__legacy-plan-management_0.snap @@ -55,11 +55,11 @@ trace: performance: "[perf]" traceData: customer: - result: "null" + result: ~ plan: - result: "null" + result: ~ planDetails: - result: "null" + result: ~ migrationEligibility: id: migrationEligibility input: diff --git a/core/engine/tests/snapshots/engine__loan-approval_0.snap b/core/engine/tests/snapshots/engine__loan-approval_0.snap index 340cd848..232ba4c3 100644 --- a/core/engine/tests/snapshots/engine__loan-approval_0.snap +++ b/core/engine/tests/snapshots/engine__loan-approval_0.snap @@ -70,7 +70,8 @@ trace: performance: "[perf]" traceData: dtiRatio: - result: "30" + result: + "$serde_json::private::Number": "30" calculateInterestRate: id: calculateInterestRate input: @@ -118,15 +119,19 @@ trace: performance: "[perf]" traceData: approval: - result: "true" + result: true baseRate: - result: "5.5" + result: + "$serde_json::private::Number": "5.5" interestRate: - result: "6.5" + result: + "$serde_json::private::Number": "6.5" riskAdjustment: - result: "20" + result: + "$serde_json::private::Number": "20" totalRiskScore: - result: "80" + result: + "$serde_json::private::Number": "80" determineApproval: id: determineApproval input: diff --git a/core/engine/tests/snapshots/engine__marketplace-listing-verification-system_0.snap b/core/engine/tests/snapshots/engine__marketplace-listing-verification-system_0.snap index 6bb0c09f..0aab44a0 100644 --- a/core/engine/tests/snapshots/engine__marketplace-listing-verification-system_0.snap +++ b/core/engine/tests/snapshots/engine__marketplace-listing-verification-system_0.snap @@ -123,17 +123,18 @@ trace: performance: "[perf]" traceData: hasLowRating: - result: "true" + result: true hasPreviousViolations: - result: "true" + result: true isHighValueBrand: - result: "true" + result: true isNewSeller: - result: "true" + result: true isSensitiveCategory: - result: "true" + result: true priceDeviationScore: - result: "36.66666666666666666666666667" + result: + "$serde_json::private::Number": "36.66666666666666666666666667" determineAction: id: determineAction input: diff --git a/core/engine/tests/snapshots/engine__marketplace-seller-grading-system_0.snap b/core/engine/tests/snapshots/engine__marketplace-seller-grading-system_0.snap index 06292120..c59d2730 100644 --- a/core/engine/tests/snapshots/engine__marketplace-seller-grading-system_0.snap +++ b/core/engine/tests/snapshots/engine__marketplace-seller-grading-system_0.snap @@ -225,8 +225,8 @@ trace: inventory: "$serde_json::private::Number": "4" strengths: - - customerSatisfaction - inventory + - customerSatisfaction - delivery sellerInfo: id: S12345 @@ -302,8 +302,8 @@ trace: inventory: "$serde_json::private::Number": "4" strengths: - - customerSatisfaction - inventory + - customerSatisfaction - delivery sellerInfo: id: S12345 @@ -313,11 +313,15 @@ trace: performance: "[perf]" traceData: averageScore: - result: "3.75" + result: + "$serde_json::private::Number": "3.75" improvements: - result: "[]" + result: [] strengths: - result: "[\"customerSatisfaction\",\"inventory\",\"delivery\"]" + result: + - inventory + - customerSatisfaction + - delivery ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__medical-appointment-priority-system_0.snap b/core/engine/tests/snapshots/engine__medical-appointment-priority-system_0.snap deleted file mode 100644 index 14a2d0d5..00000000 --- a/core/engine/tests/snapshots/engine__medical-appointment-priority-system_0.snap +++ /dev/null @@ -1,391 +0,0 @@ ---- -source: core/engine/tests/engine.rs -expression: serialized_result ---- -performance: "[perf]" -result: - priorityFactors: - - Moderate condition with follow-up - - Moderate wait time (8-14 days) - - Age over 65 - - Chronic condition - - Recent hospitalization - result: - priority: HIGH - recommendation: Schedule within 24-48 hours - scores: - conditionSeverity: - "$serde_json::private::Number": "20" - riskFactors: - "$serde_json::private::Number": "40" - waitTime: - "$serde_json::private::Number": "10" - totalScore: - "$serde_json::private::Number": "70" -trace: - 02b0be40-dfe0-4a11-a9a4-17f66823f0c2: - id: 02b0be40-dfe0-4a11-a9a4-17f66823f0c2 - input: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - riskFactors: - - message: Age over 65 - score: - "$serde_json::private::Number": "10" - - message: Chronic condition - score: - "$serde_json::private::Number": "15" - - message: Recent hospitalization - score: - "$serde_json::private::Number": "15" - name: riskFactorSummary - order: - "$serde_json::private::Number": "2" - output: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - reasons: - riskFactors: - - Age over 65 - - Chronic condition - - Recent hospitalization - scores: - riskFactors: - "$serde_json::private::Number": "40" - performance: "[perf]" - traceData: - reasons.riskFactors: - result: "[\"Age over 65\",\"Chronic condition\",\"Recent hospitalization\"]" - riskFactors: - result: "null" - scores.riskFactors: - result: "40" - conditionSeverityNode: - id: conditionSeverityNode - input: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - reasons: - riskFactors: - - Age over 65 - - Chronic condition - - Recent hospitalization - scores: - riskFactors: - "$serde_json::private::Number": "40" - name: evaluateConditionSeverity - order: - "$serde_json::private::Number": "3" - output: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - reasons: - conditionSeverity: Moderate condition with follow-up - riskFactors: - - Age over 65 - - Chronic condition - - Recent hospitalization - scores: - conditionSeverity: - "$serde_json::private::Number": "20" - riskFactors: - "$serde_json::private::Number": "40" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "2" - reference_map: - appointment.conditionSeverity: moderate - appointment.isFollowUp: true - rule: - _id: severity3 - "appointment.conditionSeverity[i2-1]": "'moderate'" - "appointment.isFollowUp[i2-2]": "true" - inputNode: - id: inputNode - input: ~ - name: request - order: - "$serde_json::private::Number": "0" - output: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - performance: "[perf]" - traceData: ~ - priorityAssignmentNode: - id: priorityAssignmentNode - input: - priorityFactors: - - Moderate condition with follow-up - - Moderate wait time (8-14 days) - - Age over 65 - - Chronic condition - - Recent hospitalization - scores: - conditionSeverity: - "$serde_json::private::Number": "20" - riskFactors: - "$serde_json::private::Number": "40" - waitTime: - "$serde_json::private::Number": "10" - totalScore: - "$serde_json::private::Number": "70" - name: assignPriorityLevel - order: - "$serde_json::private::Number": "6" - output: - priorityFactors: - - Moderate condition with follow-up - - Moderate wait time (8-14 days) - - Age over 65 - - Chronic condition - - Recent hospitalization - result: - priority: HIGH - recommendation: Schedule within 24-48 hours - scores: - conditionSeverity: - "$serde_json::private::Number": "20" - riskFactors: - "$serde_json::private::Number": "40" - waitTime: - "$serde_json::private::Number": "10" - totalScore: - "$serde_json::private::Number": "70" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "1" - reference_map: - totalScore: - "$serde_json::private::Number": "70" - rule: - _id: priority2 - "totalScore[i4-1]": ">= 60" - riskFactorScoreNode: - id: riskFactorScoreNode - input: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - name: calculateRiskFactorScore - order: - "$serde_json::private::Number": "1" - output: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - riskFactors: - - message: Age over 65 - score: - "$serde_json::private::Number": "10" - - message: Chronic condition - score: - "$serde_json::private::Number": "15" - - message: Recent hospitalization - score: - "$serde_json::private::Number": "15" - performance: "[perf]" - traceData: - - index: - "$serde_json::private::Number": "0" - reference_map: {} - rule: - _description: "" - _id: risk1 - - index: - "$serde_json::private::Number": "1" - reference_map: {} - rule: - _description: "" - _id: risk2 - - index: - "$serde_json::private::Number": "3" - reference_map: {} - rule: - _description: "" - _id: risk4 - totalPriorityScoreNode: - id: totalPriorityScoreNode - input: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - reasons: - conditionSeverity: Moderate condition with follow-up - riskFactors: - - Age over 65 - - Chronic condition - - Recent hospitalization - waitTime: Moderate wait time (8-14 days) - scores: - conditionSeverity: - "$serde_json::private::Number": "20" - riskFactors: - "$serde_json::private::Number": "40" - waitTime: - "$serde_json::private::Number": "10" - name: calculateTotalPriorityScore - order: - "$serde_json::private::Number": "5" - output: - priorityFactors: - - Moderate condition with follow-up - - Moderate wait time (8-14 days) - - Age over 65 - - Chronic condition - - Recent hospitalization - scores: - conditionSeverity: - "$serde_json::private::Number": "20" - riskFactors: - "$serde_json::private::Number": "40" - waitTime: - "$serde_json::private::Number": "10" - totalScore: - "$serde_json::private::Number": "70" - performance: "[perf]" - traceData: - appointment: - result: "null" - patient: - result: "null" - priorityFactors: - result: "[\"Moderate condition with follow-up\",\"Moderate wait time (8-14 days)\",\"Age over 65\",\"Chronic condition\",\"Recent hospitalization\"]" - reasons: - result: "null" - totalScore: - result: "70" - waitTimeScoreNode: - id: waitTimeScoreNode - input: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - reasons: - conditionSeverity: Moderate condition with follow-up - riskFactors: - - Age over 65 - - Chronic condition - - Recent hospitalization - scores: - conditionSeverity: - "$serde_json::private::Number": "20" - riskFactors: - "$serde_json::private::Number": "40" - name: calculateWaitTimeScore - order: - "$serde_json::private::Number": "4" - output: - appointment: - conditionSeverity: moderate - daysWaiting: - "$serde_json::private::Number": "12" - isFollowUp: true - patient: - age: - "$serde_json::private::Number": "72" - hasChronicCondition: true - immunocompromised: false - recentHospitalization: true - reasons: - conditionSeverity: Moderate condition with follow-up - riskFactors: - - Age over 65 - - Chronic condition - - Recent hospitalization - waitTime: Moderate wait time (8-14 days) - scores: - conditionSeverity: - "$serde_json::private::Number": "20" - riskFactors: - "$serde_json::private::Number": "40" - waitTime: - "$serde_json::private::Number": "10" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "2" - reference_map: - appointment.daysWaiting: - "$serde_json::private::Number": "12" - rule: - _id: wait3 - "appointment.daysWaiting[i3-1]": "> 7" diff --git a/core/engine/tests/snapshots/engine__medication-dosage-calculator_0.snap b/core/engine/tests/snapshots/engine__medication-dosage-calculator_0.snap index 60486f12..7f89dffc 100644 --- a/core/engine/tests/snapshots/engine__medication-dosage-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__medication-dosage-calculator_0.snap @@ -122,21 +122,25 @@ trace: performance: "[perf]" traceData: hasLiverImpairment: - result: "false" + result: false hasRenalImpairment: - result: "true" + result: true isChild: - result: "false" + result: false isElderly: - result: "true" + result: true liverAdjustmentFactor: - result: "1" + result: + "$serde_json::private::Number": "1" renalAdjustmentFactor: - result: "0.75" + result: + "$serde_json::private::Number": "0.75" weightFactorAdult: - result: "0.9285714285714285714285714286" + result: + "$serde_json::private::Number": "0.9285714285714285714285714286" weightFactorChild: - result: "2.1666666666666666666666666667" + result: + "$serde_json::private::Number": "2.1666666666666666666666666667" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__municipal-permit-evaluation-system_0.snap b/core/engine/tests/snapshots/engine__municipal-permit-evaluation-system_0.snap index 9b91b508..7ecf514a 100644 --- a/core/engine/tests/snapshots/engine__municipal-permit-evaluation-system_0.snap +++ b/core/engine/tests/snapshots/engine__municipal-permit-evaluation-system_0.snap @@ -230,15 +230,15 @@ trace: performance: "[perf]" traceData: isCommercialZone: - result: "false" + result: false isIndoorEvent: - result: "false" + result: false isIndustrialZone: - result: "false" + result: false isOutdoorEvent: - result: "false" + result: false isResidentialZone: - result: "true" + result: true ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__nested-request_0.snap b/core/engine/tests/snapshots/engine__nested-request_0.snap index bd7f2faf..41220766 100644 --- a/core/engine/tests/snapshots/engine__nested-request_0.snap +++ b/core/engine/tests/snapshots/engine__nested-request_0.snap @@ -21,7 +21,7 @@ trace: performance: "[perf]" traceData: nodeData: - result: "{}" + result: {} 2a8241f2-a808-4030-afd3-94ba60d93291: id: 2a8241f2-a808-4030-afd3-94ba60d93291 input: ~ @@ -45,9 +45,9 @@ trace: performance: "[perf]" traceData: L1.carbon_accounting.score_commentary: - result: "\"There is likely to be\"" + result: There is likely to be L1.carbon_accounting.score_label: - result: "\"Moderate risk\"" + result: Moderate risk d438419f-c54a-49b4-b2a0-3bb626b0617f: id: d438419f-c54a-49b4-b2a0-3bb626b0617f input: {} @@ -59,4 +59,4 @@ trace: performance: "[perf]" traceData: L1: - result: "{}" + result: {} diff --git a/core/engine/tests/snapshots/engine__online-checkin-eligibility_0.snap b/core/engine/tests/snapshots/engine__online-checkin-eligibility_0.snap index a69d5132..4a978f56 100644 --- a/core/engine/tests/snapshots/engine__online-checkin-eligibility_0.snap +++ b/core/engine/tests/snapshots/engine__online-checkin-eligibility_0.snap @@ -122,13 +122,16 @@ trace: performance: "[perf]" traceData: currentTime: - result: "1742459400" + result: + "$serde_json::private::Number": "1742459400" flightDepartureTime: - result: "1742466600" + result: + "$serde_json::private::Number": "1742466600" hasRequiredDocuments: - result: "true" + result: true hoursUntilDeparture: - result: "2" + result: + "$serde_json::private::Number": "2" ex2: id: ex2 input: @@ -170,15 +173,15 @@ trace: performance: "[perf]" traceData: canAddBaggage: - result: "true" + result: true canSelectSeat: - result: "true" + result: true isEligible: - result: "false" + result: false message: - result: "\"You are eligible for online check-in.\"" + result: You are eligible for online check-in. statusCode: - result: "\"eligible\"" + result: eligible ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__order-consolidation-system_0.snap b/core/engine/tests/snapshots/engine__order-consolidation-system_0.snap index f6723452..0429732e 100644 --- a/core/engine/tests/snapshots/engine__order-consolidation-system_0.snap +++ b/core/engine/tests/snapshots/engine__order-consolidation-system_0.snap @@ -328,13 +328,16 @@ trace: performance: "[perf]" traceData: canConsolidate: - result: "true" + result: true consolidationWeight: - result: "20.7" + result: + "$serde_json::private::Number": "20.7" costSavingEstimate: - result: "23.75" + result: + "$serde_json::private::Number": "23.75" expectedFuelSavings: - result: "5.25" + result: + "$serde_json::private::Number": "5.25" ex2: id: ex2 input: @@ -478,13 +481,22 @@ trace: performance: "[perf]" traceData: consolidationAction: - result: "\"immediate_consolidation\"" + result: immediate_consolidation costSavingsReport: - result: "{\"fuelSavings\":5.25,\"laborSavings\":23.75,\"totalSavings\":29}" + result: + fuelSavings: + "$serde_json::private::Number": "5.25" + laborSavings: + "$serde_json::private::Number": "23.75" + totalSavings: + "$serde_json::private::Number": "29" deliverySchedule: - result: "{\"estimatedDeliveryTime\":null,\"type\":\"consolidated\",\"notificationRequired\":false}" + result: + estimatedDeliveryTime: ~ + notificationRequired: false + type: consolidated schedulingPriority: - result: "\"high\"" + result: high ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__partner-revenue-sharing_0.snap b/core/engine/tests/snapshots/engine__partner-revenue-sharing_0.snap index d378284f..7d59ae90 100644 --- a/core/engine/tests/snapshots/engine__partner-revenue-sharing_0.snap +++ b/core/engine/tests/snapshots/engine__partner-revenue-sharing_0.snap @@ -96,17 +96,23 @@ trace: performance: "[perf]" traceData: baseCommission: - result: "525000" + result: + "$serde_json::private::Number": "525000" bonusCommission: - result: "37950" + result: + "$serde_json::private::Number": "37950" durationMultiplier: - result: "1.1" + result: + "$serde_json::private::Number": "1.1" segmentMultiplier: - result: "1.15" + result: + "$serde_json::private::Number": "1.15" telcoRevenue: - result: "937050" + result: + "$serde_json::private::Number": "937050" totalCommission: - result: "562950" + result: + "$serde_json::private::Number": "562950" ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__patient-triage-system_0.snap b/core/engine/tests/snapshots/engine__patient-triage-system_0.snap index f6f5a304..1f242199 100644 --- a/core/engine/tests/snapshots/engine__patient-triage-system_0.snap +++ b/core/engine/tests/snapshots/engine__patient-triage-system_0.snap @@ -55,9 +55,9 @@ trace: scores.vitalScore + scores.symptomScore + scores.complaintScore: "$serde_json::private::Number": "40" values(flags): + - green - orange - orange - - green rule: _id: cp3 "scores.vitalScore + scores.symptomScore + scores.complaintScore[i2]": ">= 40" diff --git a/core/engine/tests/snapshots/engine__payment-routing-and-fee-calculator_0.snap b/core/engine/tests/snapshots/engine__payment-routing-and-fee-calculator_0.snap index 3772bdd2..31df1e34 100644 --- a/core/engine/tests/snapshots/engine__payment-routing-and-fee-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__payment-routing-and-fee-calculator_0.snap @@ -355,13 +355,17 @@ trace: performance: "[perf]" traceData: fee.final_amount: - result: "72.5" + result: + "$serde_json::private::Number": "72.5" fee_amount: - result: "72.5" + result: + "$serde_json::private::Number": "72.5" final_fee_percentage: - result: "2.9" + result: + "$serde_json::private::Number": "2.9" payment.net_amount: - result: "2427.5" + result: + "$serde_json::private::Number": "2427.5" payment-input: id: payment-input input: ~ @@ -573,12 +577,19 @@ trace: performance: "[perf]" traceData: routing.processing_instructions: - result: "{\"priority\":\"medium\",\"velocity_check\":true,\"fraud_scan\":\"standard\",\"manual_review\":true,\"verification_required\":\"3ds\",\"processor\":\"credit_processor\"}" + result: + fraud_scan: standard + manual_review: true + priority: medium + processor: credit_processor + velocity_check: true + verification_required: 3ds security.fraud_scan_level: - result: "\"standard\"" + result: standard security.high_risk_flag: - result: "true" + result: true security.total_risk_score: - result: "50" + result: + "$serde_json::private::Number": "50" security.velocity_check_required: - result: "true" + result: true diff --git a/core/engine/tests/snapshots/engine__policy-discount-calculator_0.snap b/core/engine/tests/snapshots/engine__policy-discount-calculator_0.snap index 7fd89e66..f844e49c 100644 --- a/core/engine/tests/snapshots/engine__policy-discount-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__policy-discount-calculator_0.snap @@ -339,8 +339,11 @@ trace: performance: "[perf]" traceData: finalPremium: - result: "900" + result: + "$serde_json::private::Number": "900" maximumDiscountPercentage: - result: "25" + result: + "$serde_json::private::Number": "25" totalDiscountPercentage: - result: "25" + result: + "$serde_json::private::Number": "25" diff --git a/core/engine/tests/snapshots/engine__policy-eligibility-analyzer_0.snap b/core/engine/tests/snapshots/engine__policy-eligibility-analyzer_0.snap index 9b507f14..84ff158b 100644 --- a/core/engine/tests/snapshots/engine__policy-eligibility-analyzer_0.snap +++ b/core/engine/tests/snapshots/engine__policy-eligibility-analyzer_0.snap @@ -151,11 +151,13 @@ trace: performance: "[perf]" traceData: denialReasons: - result: "[]" + result: [] isEligible: - result: "true" + result: true policyDecision: - result: "{\"reasons\":null,\"approved\":null}" + result: + approved: ~ + reasons: ~ input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__portfolio-risk-monitor_0.snap b/core/engine/tests/snapshots/engine__portfolio-risk-monitor_0.snap deleted file mode 100644 index 9a57fd53..00000000 --- a/core/engine/tests/snapshots/engine__portfolio-risk-monitor_0.snap +++ /dev/null @@ -1,1415 +0,0 @@ ---- -source: core/engine/tests/engine.rs -expression: serialized_result ---- -performance: "[perf]" -result: - action: rebalance - outcome: - riskScore: - "$serde_json::private::Number": "0.53" - status: rebalance_suggested - timestamp: "2025-08-20T09:43:13.406Z" - rebalanceDetails: - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - customerId: cust-78945 - date: 2025-08-20 - driftPercentage: "5.0" - message: "Rebalancing recommended: Portfolio has drifted 5.0% from target allocation." - portfolioId: port-12345 - riskCategory: high - riskScore: - "$serde_json::private::Number": "0.53" - suggestedChanges: - bonds: - "$serde_json::private::Number": "10" - cash: - "$serde_json::private::Number": "-5" - equity: - "$serde_json::private::Number": "-5" - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" -trace: - actionDeterminationSwitch: - id: actionDeterminationSwitch - input: - assessment: - exposureFactor: - "$serde_json::private::Number": "0.5" - exposureLevel: elevated - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - volatilityFactor: - "$serde_json::private::Number": "0.4" - volatilityLevel: moderate - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - exposureWeight: - "$serde_json::private::Number": "0.4" - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - marketWeight: - "$serde_json::private::Number": "0.3" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - portfolioDrift: - "$serde_json::private::Number": "5" - riskCategory: high - riskScore: - "$serde_json::private::Number": "0.53" - volatilityWeight: - "$serde_json::private::Number": "0.3" - name: determineAction - order: - "$serde_json::private::Number": "5" - output: - assessment: - exposureFactor: - "$serde_json::private::Number": "0.5" - exposureLevel: elevated - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - volatilityFactor: - "$serde_json::private::Number": "0.4" - volatilityLevel: moderate - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - exposureWeight: - "$serde_json::private::Number": "0.4" - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - marketWeight: - "$serde_json::private::Number": "0.3" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - portfolioDrift: - "$serde_json::private::Number": "5" - riskCategory: high - riskScore: - "$serde_json::private::Number": "0.53" - volatilityWeight: - "$serde_json::private::Number": "0.3" - performance: "[perf]" - traceData: - statements: - - id: rebalanceAction - inputNode: - id: inputNode - input: ~ - name: request - order: - "$serde_json::private::Number": "0" - output: - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - performance: "[perf]" - traceData: ~ - marketConditionsTable: - id: marketConditionsTable - input: - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - name: marketConditionsAssessment - order: - "$serde_json::private::Number": "1" - output: - assessment: - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "1" - reference_map: - market.trendPercentage: - "$serde_json::private::Number": "-12.5" - market.volatilityIndex: - "$serde_json::private::Number": "28.5" - rule: - _id: rule2 - "market.trendPercentage[i1-2]": "< -10" - "market.volatilityIndex[i1-1]": "> 25" - portfolioExposureTable: - id: portfolioExposureTable - input: - assessment: - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - name: portfolioExposureAssessment - order: - "$serde_json::private::Number": "2" - output: - assessment: - exposureFactor: - "$serde_json::private::Number": "0.5" - exposureLevel: elevated - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "2" - reference_map: - portfolio.highRiskPercentage: - "$serde_json::private::Number": "35" - rule: - _id: rule3 - "portfolio.highRiskPercentage[i1-1]": "> 30" - portfolioVolatilityTable: - id: portfolioVolatilityTable - input: - assessment: - exposureFactor: - "$serde_json::private::Number": "0.5" - exposureLevel: elevated - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - name: portfolioVolatilityAssessment - order: - "$serde_json::private::Number": "3" - output: - assessment: - exposureFactor: - "$serde_json::private::Number": "0.5" - exposureLevel: elevated - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - volatilityFactor: - "$serde_json::private::Number": "0.4" - volatilityLevel: moderate - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - performance: "[perf]" - traceData: - index: - "$serde_json::private::Number": "2" - reference_map: - assessment.marketRiskFactor: - "$serde_json::private::Number": "0.7" - portfolio.volatility: - "$serde_json::private::Number": "22.5" - rule: - _id: rule3 - "assessment.marketRiskFactor[i1-2]": "" - "portfolio.volatility[i1-1]": "> 20" - rebalanceFunction: - id: rebalanceFunction - input: - assessment: - exposureFactor: - "$serde_json::private::Number": "0.5" - exposureLevel: elevated - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - volatilityFactor: - "$serde_json::private::Number": "0.4" - volatilityLevel: moderate - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - exposureWeight: - "$serde_json::private::Number": "0.4" - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - marketWeight: - "$serde_json::private::Number": "0.3" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - portfolioDrift: - "$serde_json::private::Number": "5" - riskCategory: high - riskScore: - "$serde_json::private::Number": "0.53" - volatilityWeight: - "$serde_json::private::Number": "0.3" - name: suggestRebalancing - order: - "$serde_json::private::Number": "6" - output: - action: rebalance - outcome: - riskScore: - "$serde_json::private::Number": "0.53" - status: rebalance_suggested - timestamp: "2025-08-20T09:43:13.406Z" - rebalanceDetails: - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - customerId: cust-78945 - date: 2025-08-20 - driftPercentage: "5.0" - message: "Rebalancing recommended: Portfolio has drifted 5.0% from target allocation." - portfolioId: port-12345 - riskCategory: high - riskScore: - "$serde_json::private::Number": "0.53" - suggestedChanges: - bonds: - "$serde_json::private::Number": "10" - cash: - "$serde_json::private::Number": "-5" - equity: - "$serde_json::private::Number": "-5" - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - performance: "[perf]" - traceData: - log: [] - riskScoreCalculation: - id: riskScoreCalculation - input: - assessment: - exposureFactor: - "$serde_json::private::Number": "0.5" - exposureLevel: elevated - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - volatilityFactor: - "$serde_json::private::Number": "0.4" - volatilityLevel: moderate - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - name: calculateRiskScore - order: - "$serde_json::private::Number": "4" - output: - assessment: - exposureFactor: - "$serde_json::private::Number": "0.5" - exposureLevel: elevated - marketAssessment: Elevated volatility with substantial market decline - marketCondition: high - marketRiskFactor: - "$serde_json::private::Number": "0.7" - volatilityFactor: - "$serde_json::private::Number": "0.4" - volatilityLevel: moderate - customer: - id: cust-78945 - investmentHorizon: long-term - name: John Smith - preferences: - alertThreshold: moderate - allowAutomaticAdjustments: true - communicationPreference: email - riskTolerance: moderate - exposureWeight: - "$serde_json::private::Number": "0.4" - market: - economicIndicators: - gdpGrowth: - "$serde_json::private::Number": "0.8" - inflation: - "$serde_json::private::Number": "4.2" - unemploymentRate: - "$serde_json::private::Number": "4.1" - interestRate: - "$serde_json::private::Number": "3.75" - sectorPerformance: - consumerStaples: - "$serde_json::private::Number": "-3.2" - financials: - "$serde_json::private::Number": "-18.4" - healthcare: - "$serde_json::private::Number": "-5.1" - technology: - "$serde_json::private::Number": "-15.2" - utilities: - "$serde_json::private::Number": "1.5" - trendPercentage: - "$serde_json::private::Number": "-12.5" - volatilityIndex: - "$serde_json::private::Number": "28.5" - marketWeight: - "$serde_json::private::Number": "0.3" - portfolio: - creationDate: 2019-05-12 - currentAllocation: - bonds: - "$serde_json::private::Number": "25" - cash: - "$serde_json::private::Number": "10" - equity: - "$serde_json::private::Number": "65" - highRiskPercentage: - "$serde_json::private::Number": "35" - holdings: - - category: equity - percentage: - "$serde_json::private::Number": "30" - symbol: VTI - value: - "$serde_json::private::Number": "225000" - - category: equity - percentage: - "$serde_json::private::Number": "20" - symbol: VXUS - value: - "$serde_json::private::Number": "150000" - - category: equity - percentage: - "$serde_json::private::Number": "15" - symbol: VGT - value: - "$serde_json::private::Number": "112500" - - category: bonds - percentage: - "$serde_json::private::Number": "25" - symbol: BND - value: - "$serde_json::private::Number": "187500" - - category: cash - percentage: - "$serde_json::private::Number": "10" - symbol: CASH - value: - "$serde_json::private::Number": "75000" - id: port-12345 - lastRebalance: - "$serde_json::private::Number": "95" - name: Retirement Portfolio - targetAllocation: - bonds: - "$serde_json::private::Number": "35" - cash: - "$serde_json::private::Number": "5" - equity: - "$serde_json::private::Number": "60" - totalValue: - "$serde_json::private::Number": "750000" - volatility: - "$serde_json::private::Number": "22.5" - portfolioDrift: - "$serde_json::private::Number": "5" - riskCategory: high - riskScore: - "$serde_json::private::Number": "0.53" - volatilityWeight: - "$serde_json::private::Number": "0.3" - performance: "[perf]" - traceData: - exposureWeight: - result: "0.4" - marketWeight: - result: "0.3" - portfolioDrift: - result: "5" - riskCategory: - result: "\"high\"" - riskScore: - result: "0.53" - volatilityWeight: - result: "0.3" diff --git a/core/engine/tests/snapshots/engine__preventive-care-recommendation_0.snap b/core/engine/tests/snapshots/engine__preventive-care-recommendation_0.snap deleted file mode 100644 index 87c8dd4e..00000000 --- a/core/engine/tests/snapshots/engine__preventive-care-recommendation_0.snap +++ /dev/null @@ -1,298 +0,0 @@ ---- -source: core/engine/tests/engine.rs -expression: serialized_result ---- -performance: "[perf]" -result: - patientName: Jane Smith - recommendationDate: "2025-08-20 09:43:15" - summarizedRecommendations: - - riskBasedRecommendations: Earlier and more frequent diabetes screening - - riskBasedRecommendations: Earlier and more frequent mammograms - - riskBasedRecommendations: Lung cancer screening - - ageBasedRecommendations: - primary: Blood pressure screening - quaternary: Eye exam every 2-4 years - secondary: Cholesterol screening every 5 years - tertiary: Diabetes screening every 3 years - - genderBasedRecommendations: - primary: Mammogram every 1-2 years (discuss with doctor) - secondary: Cervical cancer screening every 3 years - totalRecommendations: - "$serde_json::private::Number": "5" -trace: - ageSpecificScreenings: - id: ageSpecificScreenings - input: - age: - "$serde_json::private::Number": "42" - familyHistory: - - breast cancer - - diabetes - firstName: Jane - lastCheckup: 2023-10-15 - lastName: Smith - riskFactors: - - smoking - sex: female - name: ageBasedRecommendations - order: - "$serde_json::private::Number": "1" - output: - age: - "$serde_json::private::Number": "42" - familyHistory: - - breast cancer - - diabetes - firstName: Jane - lastCheckup: 2023-10-15 - lastName: Smith - recommendations: - age: - - recommendations: - ageBasedRecommendations: - primary: Blood pressure screening - quaternary: Eye exam every 2-4 years - secondary: Cholesterol screening every 5 years - tertiary: Diabetes screening every 3 years - riskFactors: - - smoking - sex: female - performance: "[perf]" - traceData: - - index: - "$serde_json::private::Number": "2" - reference_map: - age: - "$serde_json::private::Number": "42" - rule: - _id: age3 - "age[i1]": ">= 40 and < 50" - genderSpecificScreenings: - id: genderSpecificScreenings - input: - age: - "$serde_json::private::Number": "42" - familyHistory: - - breast cancer - - diabetes - firstName: Jane - lastCheckup: 2023-10-15 - lastName: Smith - recommendations: - age: - - recommendations: - ageBasedRecommendations: - primary: Blood pressure screening - quaternary: Eye exam every 2-4 years - secondary: Cholesterol screening every 5 years - tertiary: Diabetes screening every 3 years - riskFactors: - - smoking - sex: female - name: sexBasedRecommendations - order: - "$serde_json::private::Number": "2" - output: - age: - "$serde_json::private::Number": "42" - familyHistory: - - breast cancer - - diabetes - firstName: Jane - lastCheckup: 2023-10-15 - lastName: Smith - recommendations: - age: - - recommendations: - ageBasedRecommendations: - primary: Blood pressure screening - quaternary: Eye exam every 2-4 years - secondary: Cholesterol screening every 5 years - tertiary: Diabetes screening every 3 years - sex: - - recommendations: - genderBasedRecommendations: - primary: Mammogram every 1-2 years (discuss with doctor) - secondary: Cervical cancer screening every 3 years - riskFactors: - - smoking - sex: female - performance: "[perf]" - traceData: - - index: - "$serde_json::private::Number": "2" - reference_map: - age: - "$serde_json::private::Number": "42" - sex: female - rule: - _id: gender3 - "age[i2]": "[40..50)" - "sex[i1]": "'female'" - generateRecommendations: - id: generateRecommendations - input: - age: - "$serde_json::private::Number": "42" - familyHistory: - - breast cancer - - diabetes - firstName: Jane - lastCheckup: 2023-10-15 - lastName: Smith - recommendations: - age: - - recommendations: - ageBasedRecommendations: - primary: Blood pressure screening - quaternary: Eye exam every 2-4 years - secondary: Cholesterol screening every 5 years - tertiary: Diabetes screening every 3 years - risk: - - recommendations: - riskBasedRecommendations: Earlier and more frequent diabetes screening - - recommendations: - riskBasedRecommendations: Earlier and more frequent mammograms - - recommendations: - riskBasedRecommendations: Lung cancer screening - sex: - - recommendations: - genderBasedRecommendations: - primary: Mammogram every 1-2 years (discuss with doctor) - secondary: Cervical cancer screening every 3 years - riskFactors: - - smoking - sex: female - name: finalRecommendations - order: - "$serde_json::private::Number": "4" - output: - patientName: Jane Smith - recommendationDate: "2025-08-20 09:43:15" - summarizedRecommendations: - - riskBasedRecommendations: Earlier and more frequent diabetes screening - - riskBasedRecommendations: Earlier and more frequent mammograms - - riskBasedRecommendations: Lung cancer screening - - ageBasedRecommendations: - primary: Blood pressure screening - quaternary: Eye exam every 2-4 years - secondary: Cholesterol screening every 5 years - tertiary: Diabetes screening every 3 years - - genderBasedRecommendations: - primary: Mammogram every 1-2 years (discuss with doctor) - secondary: Cervical cancer screening every 3 years - testResults: ~ - totalRecommendations: - "$serde_json::private::Number": "5" - performance: "[perf]" - traceData: - patientName: - result: "\"Jane Smith\"" - recommendationDate: - result: "\"2025-08-20 09:43:15\"" - summarizedRecommendations: - result: "[{\"riskBasedRecommendations\":\"Earlier and more frequent diabetes screening\"},{\"riskBasedRecommendations\":\"Earlier and more frequent mammograms\"},{\"riskBasedRecommendations\":\"Lung cancer screening\"},{\"ageBasedRecommendations\":{\"tertiary\":\"Diabetes screening every 3 years\",\"primary\":\"Blood pressure screening\",\"quaternary\":\"Eye exam every 2-4 years\",\"secondary\":\"Cholesterol screening every 5 years\"}},{\"genderBasedRecommendations\":{\"secondary\":\"Cervical cancer screening every 3 years\",\"primary\":\"Mammogram every 1-2 years (discuss with doctor)\"}}]" - testResults: - result: "null" - totalRecommendations: - result: "5" - input: - id: input - input: ~ - name: patientData - order: - "$serde_json::private::Number": "0" - output: - age: - "$serde_json::private::Number": "42" - familyHistory: - - breast cancer - - diabetes - firstName: Jane - lastCheckup: 2023-10-15 - lastName: Smith - riskFactors: - - smoking - sex: female - performance: "[perf]" - traceData: ~ - riskFactorScreenings: - id: riskFactorScreenings - input: - age: - "$serde_json::private::Number": "42" - familyHistory: - - breast cancer - - diabetes - firstName: Jane - lastCheckup: 2023-10-15 - lastName: Smith - recommendations: - age: - - recommendations: - ageBasedRecommendations: - primary: Blood pressure screening - quaternary: Eye exam every 2-4 years - secondary: Cholesterol screening every 5 years - tertiary: Diabetes screening every 3 years - sex: - - recommendations: - genderBasedRecommendations: - primary: Mammogram every 1-2 years (discuss with doctor) - secondary: Cervical cancer screening every 3 years - riskFactors: - - smoking - sex: female - name: riskBasedRecommendations - order: - "$serde_json::private::Number": "3" - output: - age: - "$serde_json::private::Number": "42" - familyHistory: - - breast cancer - - diabetes - firstName: Jane - lastCheckup: 2023-10-15 - lastName: Smith - recommendations: - age: - - recommendations: - ageBasedRecommendations: - primary: Blood pressure screening - quaternary: Eye exam every 2-4 years - secondary: Cholesterol screening every 5 years - tertiary: Diabetes screening every 3 years - risk: - - recommendations: - riskBasedRecommendations: Earlier and more frequent diabetes screening - - recommendations: - riskBasedRecommendations: Earlier and more frequent mammograms - - recommendations: - riskBasedRecommendations: Lung cancer screening - sex: - - recommendations: - genderBasedRecommendations: - primary: Mammogram every 1-2 years (discuss with doctor) - secondary: Cervical cancer screening every 3 years - riskFactors: - - smoking - sex: female - performance: "[perf]" - traceData: - - index: - "$serde_json::private::Number": "0" - reference_map: {} - rule: - _id: risk1 - - index: - "$serde_json::private::Number": "3" - reference_map: {} - rule: - _id: risk4 - - index: - "$serde_json::private::Number": "4" - reference_map: {} - rule: - _id: risk5 diff --git a/core/engine/tests/snapshots/engine__product-listing-scoring_0.snap b/core/engine/tests/snapshots/engine__product-listing-scoring_0.snap index 5c473e2d..65380eb8 100644 --- a/core/engine/tests/snapshots/engine__product-listing-scoring_0.snap +++ b/core/engine/tests/snapshots/engine__product-listing-scoring_0.snap @@ -299,10 +299,29 @@ trace: performance: "[perf]" traceData: breakdown: - result: "{\"inventoryAvailability\":{\"score\":8},\"descriptionCompleteness\":{\"category\":\"good\",\"score\":25},\"keywordOptimization\":{\"score\":15},\"pricingCompetitiveness\":{\"score\":8},\"imageQuality\":{\"score\":25,\"category\":\"good\"}}" + result: + descriptionCompleteness: + category: good + score: + "$serde_json::private::Number": "25" + imageQuality: + category: good + score: + "$serde_json::private::Number": "25" + inventoryAvailability: + score: + "$serde_json::private::Number": "8" + keywordOptimization: + score: + "$serde_json::private::Number": "15" + pricingCompetitiveness: + score: + "$serde_json::private::Number": "8" maximumPossibleScore: - result: "100" + result: + "$serde_json::private::Number": "100" overallScoreCategory: - result: "\"excellent\"" + result: excellent totalScore: - result: "81" + result: + "$serde_json::private::Number": "81" diff --git a/core/engine/tests/snapshots/engine__realtime-fraud-detection_0.snap b/core/engine/tests/snapshots/engine__realtime-fraud-detection_0.snap index 31be529e..6984d76b 100644 --- a/core/engine/tests/snapshots/engine__realtime-fraud-detection_0.snap +++ b/core/engine/tests/snapshots/engine__realtime-fraud-detection_0.snap @@ -176,10 +176,11 @@ trace: performance: "[perf]" traceData: blockTransaction: - result: "false" + result: false finalRiskScore: - result: "75" + result: + "$serde_json::private::Number": "75" reason: - result: "\"Unusual location with amount significantly above average\"" + result: Unusual location with amount significantly above average requiresReview: - result: "true" + result: true diff --git a/core/engine/tests/snapshots/engine__regional-compliance-manager_0.snap b/core/engine/tests/snapshots/engine__regional-compliance-manager_0.snap index c1fd84c9..15b587a1 100644 --- a/core/engine/tests/snapshots/engine__regional-compliance-manager_0.snap +++ b/core/engine/tests/snapshots/engine__regional-compliance-manager_0.snap @@ -32,7 +32,7 @@ trace: serviceLevel: standard type: individual dataRetentionDate: - "$serde_json::private::Number": "63963682995" + "$serde_json::private::Number": "63963622502" serviceRequest: dataSharing: false internationalRoaming: true @@ -105,7 +105,7 @@ trace: serviceLevel: standard type: individual dataRetentionDate: - "$serde_json::private::Number": "63963682995" + "$serde_json::private::Number": "63963622502" serviceRequest: dataSharing: false internationalRoaming: true @@ -113,11 +113,12 @@ trace: performance: "[perf]" traceData: complianceStatus: - result: "\"compliant\"" + result: compliant complianceSummary: - result: "\"Region: EU, Framework: GDPR, Retention: 24 months\"" + result: "Region: EU, Framework: GDPR, Retention: 24 months" dataRetentionDate: - result: "63963682995" + result: + "$serde_json::private::Number": "63963622502" input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__returns-and-refund-policy_0.snap b/core/engine/tests/snapshots/engine__returns-and-refund-policy_0.snap index 1196125e..ad9c1731 100644 --- a/core/engine/tests/snapshots/engine__returns-and-refund-policy_0.snap +++ b/core/engine/tests/snapshots/engine__returns-and-refund-policy_0.snap @@ -164,13 +164,15 @@ trace: performance: "[perf]" traceData: processingTimeEstimate: - result: "5" + result: + "$serde_json::private::Number": "5" refundAmount: - result: "89.99" + result: + "$serde_json::private::Number": "89.99" refundShipping: - result: "true" + result: true returnShippingCovered: - result: "true" + result: true responsibilityDetermination: id: responsibilityDetermination input: diff --git a/core/engine/tests/snapshots/engine__returns-processing-system_0.snap b/core/engine/tests/snapshots/engine__returns-processing-system_0.snap index 36261568..3ab82fe7 100644 --- a/core/engine/tests/snapshots/engine__returns-processing-system_0.snap +++ b/core/engine/tests/snapshots/engine__returns-processing-system_0.snap @@ -154,13 +154,13 @@ trace: performance: "[perf]" traceData: isFrequentReturner: - result: "false" + result: false isHighValueCustomer: - result: "true" + result: true isHighValueItem: - result: "true" + result: true isPurchaseWithinWarranty: - result: "true" + result: true input1: id: input1 input: ~ diff --git a/core/engine/tests/snapshots/engine__school-district-resource-allocation_0.snap b/core/engine/tests/snapshots/engine__school-district-resource-allocation_0.snap index d3bc9fe3..f22ea15f 100644 --- a/core/engine/tests/snapshots/engine__school-district-resource-allocation_0.snap +++ b/core/engine/tests/snapshots/engine__school-district-resource-allocation_0.snap @@ -210,11 +210,14 @@ trace: performance: "[perf]" traceData: adjusted_funding: - result: "4537500" + result: + "$serde_json::private::Number": "4537500" performance_multiplier: - result: "1.1" + result: + "$serde_json::private::Number": "1.1" performance_score: - result: "80" + result: + "$serde_json::private::Number": "80" specialProgramsTable: id: specialProgramsTable input: diff --git a/core/engine/tests/snapshots/engine__seat-map-optimization_0.snap b/core/engine/tests/snapshots/engine__seat-map-optimization_0.snap index 3f56deac..5f67f2c0 100644 --- a/core/engine/tests/snapshots/engine__seat-map-optimization_0.snap +++ b/core/engine/tests/snapshots/engine__seat-map-optimization_0.snap @@ -78,9 +78,11 @@ trace: performance: "[perf]" traceData: adjacentSeatsNeeded: - result: "3" + result: + "$serde_json::private::Number": "3" cabinFillPercentage: - result: "60" + result: + "$serde_json::private::Number": "60" inputNode: id: inputNode input: ~ @@ -168,11 +170,12 @@ trace: performance: "[perf]" traceData: seatDisplay.displayMessage: - result: "\"Select your seats\"" + result: Select your seats seatDisplay.seatMapVersion: - result: "\"premium\"" + result: premium seatDisplay.totalAvailableSeats: - result: "72" + result: + "$serde_json::private::Number": "72" seatMapRules: id: seatMapRules input: diff --git a/core/engine/tests/snapshots/engine__seller-approval-workflow_0.snap b/core/engine/tests/snapshots/engine__seller-approval-workflow_0.snap index 256849ff..4f3dc9c1 100644 --- a/core/engine/tests/snapshots/engine__seller-approval-workflow_0.snap +++ b/core/engine/tests/snapshots/engine__seller-approval-workflow_0.snap @@ -5,7 +5,7 @@ expression: serialized_result performance: "[perf]" result: approvalDate: - "$serde_json::private::Number": "1755682992" + "$serde_json::private::Number": "1755622502" score: "$serde_json::private::Number": "85" status: APPROVED @@ -56,18 +56,20 @@ trace: "$serde_json::private::Number": "4" output: approvalDate: - "$serde_json::private::Number": "1755682992" + "$serde_json::private::Number": "1755622502" score: "$serde_json::private::Number": "85" status: APPROVED performance: "[perf]" traceData: approvalDate: - result: "1755682992" + result: + "$serde_json::private::Number": "1755622502" score: - result: "85" + result: + "$serde_json::private::Number": "85" status: - result: "\"APPROVED\"" + result: APPROVED approvalSwitch: id: approvalSwitch input: diff --git a/core/engine/tests/snapshots/engine__seller-fee-calculator_0.snap b/core/engine/tests/snapshots/engine__seller-fee-calculator_0.snap index 9f0a24d7..ab74b994 100644 --- a/core/engine/tests/snapshots/engine__seller-fee-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__seller-fee-calculator_0.snap @@ -95,11 +95,14 @@ trace: performance: "[perf]" traceData: effectiveFeeRate: - result: "0.07" + result: + "$serde_json::private::Number": "0.07" totalMonthlyFee: - result: "5139.99" + result: + "$serde_json::private::Number": "5139.99" transactionFee: - result: "5040" + result: + "$serde_json::private::Number": "5040" input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__service-level-agreement-enforcement_0.snap b/core/engine/tests/snapshots/engine__service-level-agreement-enforcement_0.snap index d7503aee..d710bc15 100644 --- a/core/engine/tests/snapshots/engine__service-level-agreement-enforcement_0.snap +++ b/core/engine/tests/snapshots/engine__service-level-agreement-enforcement_0.snap @@ -588,12 +588,15 @@ trace: performance: "[perf]" traceData: customerTier: - result: "\"premium\"" + result: premium downtimeDuration: - result: "45" + result: + "$serde_json::private::Number": "45" isDowntime: - result: "true" + result: true packetLoss: - result: "0.8" + result: + "$serde_json::private::Number": "0.8" responseTime: - result: "320" + result: + "$serde_json::private::Number": "320" diff --git a/core/engine/tests/snapshots/engine__set-fee_0.snap b/core/engine/tests/snapshots/engine__set-fee_0.snap index df9e6d22..4e23f4e6 100644 --- a/core/engine/tests/snapshots/engine__set-fee_0.snap +++ b/core/engine/tests/snapshots/engine__set-fee_0.snap @@ -39,9 +39,11 @@ trace: performance: "[perf]" traceData: cat_1: - result: "3" + result: + "$serde_json::private::Number": "3" cat_2: - result: "4" + result: + "$serde_json::private::Number": "4" 3a801d19-b611-4163-bfdd-f247a689a275: id: 3a801d19-b611-4163-bfdd-f247a689a275 input: diff --git a/core/engine/tests/snapshots/engine__set-fee_2.snap b/core/engine/tests/snapshots/engine__set-fee_2.snap index 8e78c5c8..b5862d5b 100644 --- a/core/engine/tests/snapshots/engine__set-fee_2.snap +++ b/core/engine/tests/snapshots/engine__set-fee_2.snap @@ -39,9 +39,11 @@ trace: performance: "[perf]" traceData: cat_1: - result: "3" + result: + "$serde_json::private::Number": "3" cat_2: - result: "4" + result: + "$serde_json::private::Number": "4" 3a801d19-b611-4163-bfdd-f247a689a275: id: 3a801d19-b611-4163-bfdd-f247a689a275 input: diff --git a/core/engine/tests/snapshots/engine__shipping-carrier-selector_0.snap b/core/engine/tests/snapshots/engine__shipping-carrier-selector_0.snap index 92e10b61..d91066be 100644 --- a/core/engine/tests/snapshots/engine__shipping-carrier-selector_0.snap +++ b/core/engine/tests/snapshots/engine__shipping-carrier-selector_0.snap @@ -216,17 +216,47 @@ trace: performance: "[perf]" traceData: baseCosts: - result: "{\"WorldWide\":77.5,\"EcoShip\":21.75,\"SpeedyExpress\":56.25,\"StandardCourier\":28.25,\"FastTrack\":40.5,\"RegularPost\":25,\"GlobalExpress\":87.5,\"QuickShip\":39.75,\"GlobalStandard\":60,\"HeavyHauler\":65}" + result: + EcoShip: + "$serde_json::private::Number": "21.75" + FastTrack: + "$serde_json::private::Number": "40.5" + GlobalExpress: + "$serde_json::private::Number": "87.5" + GlobalStandard: + "$serde_json::private::Number": "60" + HeavyHauler: + "$serde_json::private::Number": "65" + QuickShip: + "$serde_json::private::Number": "39.75" + RegularPost: + "$serde_json::private::Number": "25" + SpeedyExpress: + "$serde_json::private::Number": "56.25" + StandardCourier: + "$serde_json::private::Number": "28.25" + WorldWide: + "$serde_json::private::Number": "77.5" carrierCosts: - result: "[{\"cost\":40.5,\"carrier\":\"FastTrack\"},{\"carrier\":\"QuickShip\",\"cost\":39.75}]" + result: + - carrier: FastTrack + cost: + "$serde_json::private::Number": "40.5" + - carrier: QuickShip + cost: + "$serde_json::private::Number": "39.75" chargableWeight: - result: "12.5" + result: + "$serde_json::private::Number": "12.5" eligibleCarriers: - result: "[\"FastTrack\",\"QuickShip\"]" + result: + - FastTrack + - QuickShip isOversized: - result: "false" + result: false volumetricWeight: - result: "7.875" + result: + "$serde_json::private::Number": "7.875" input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__supply-chain-risk_0.snap b/core/engine/tests/snapshots/engine__supply-chain-risk_0.snap index 07ce67e7..960a7789 100644 --- a/core/engine/tests/snapshots/engine__supply-chain-risk_0.snap +++ b/core/engine/tests/snapshots/engine__supply-chain-risk_0.snap @@ -109,11 +109,14 @@ trace: performance: "[perf]" traceData: adjustedRiskScore: - result: "57" + result: + "$serde_json::private::Number": "57" geopoliticalFactor: - result: "1.3" + result: + "$serde_json::private::Number": "1.3" marketVolatilityFactor: - result: "1.1" + result: + "$serde_json::private::Number": "1.1" input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__tax-exemption_0.snap b/core/engine/tests/snapshots/engine__tax-exemption_0.snap index 542c1d0b..be95f9f0 100644 --- a/core/engine/tests/snapshots/engine__tax-exemption_0.snap +++ b/core/engine/tests/snapshots/engine__tax-exemption_0.snap @@ -102,11 +102,11 @@ trace: performance: "[perf]" traceData: result.annualFilingRequirement: - result: "\"990-EZ\"" + result: 990-EZ result.effectiveDate: - result: "\"2025-03-20\"" + result: 2025-03-20 result.publicDisclosureRequired: - result: "true" + result: true ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__traffic-violation-penalty-calculator_0.snap b/core/engine/tests/snapshots/engine__traffic-violation-penalty-calculator_0.snap index c119b577..a7aa5f63 100644 --- a/core/engine/tests/snapshots/engine__traffic-violation-penalty-calculator_0.snap +++ b/core/engine/tests/snapshots/engine__traffic-violation-penalty-calculator_0.snap @@ -87,9 +87,11 @@ trace: performance: "[perf]" traceData: assessment.final_fine: - result: "180" + result: + "$serde_json::private::Number": "180" assessment.final_points: - result: "3" + result: + "$serde_json::private::Number": "3" input: id: input input: ~ diff --git a/core/engine/tests/snapshots/engine__transaction-compliance-classifier_0.snap b/core/engine/tests/snapshots/engine__transaction-compliance-classifier_0.snap index c3d3d378..f7d05388 100644 --- a/core/engine/tests/snapshots/engine__transaction-compliance-classifier_0.snap +++ b/core/engine/tests/snapshots/engine__transaction-compliance-classifier_0.snap @@ -303,15 +303,16 @@ trace: performance: "[perf]" traceData: has_compliance_flags: - result: "false" + result: false report_instructions: - result: "\"File FinCEN Form 112 within 24 hours\"" + result: File FinCEN Form 112 within 24 hours reporting_deadline: - result: "1743330600" + result: + "$serde_json::private::Number": "1743330600" reporting_status: - result: "\"urgent_filing_required\"" + result: urgent_filing_required requires_immediate_filing: - result: "true" + result: true risk_assessment: id: risk_assessment input: @@ -404,17 +405,23 @@ trace: performance: "[perf]" traceData: amount_score: - result: "15" + result: + "$serde_json::private::Number": "15" base_risk_score: - result: "0" + result: + "$serde_json::private::Number": "0" customer_score: - result: "0" + result: + "$serde_json::private::Number": "0" priority_score: - result: "25" + result: + "$serde_json::private::Number": "25" total_risk_score: - result: "55" + result: + "$serde_json::private::Number": "55" transaction_history_score: - result: "0" + result: + "$serde_json::private::Number": "0" threshold_checks: id: threshold_checks input: diff --git a/core/engine/tests/snapshots/engine__warehouse-cross-docking_0.snap b/core/engine/tests/snapshots/engine__warehouse-cross-docking_0.snap index f06192e7..7e7a969b 100644 --- a/core/engine/tests/snapshots/engine__warehouse-cross-docking_0.snap +++ b/core/engine/tests/snapshots/engine__warehouse-cross-docking_0.snap @@ -185,11 +185,13 @@ trace: performance: "[perf]" traceData: hasMatchingOutboundOrders: - result: "true" + result: true timeDifferenceHours: - result: "23" + result: + "$serde_json::private::Number": "23" warehouseCapacityPercentage: - result: "75" + result: + "$serde_json::private::Number": "75" ex2: id: ex2 input: @@ -266,11 +268,12 @@ trace: performance: "[perf]" traceData: dockingBay: - result: "\"Bay-E4\"" + result: Bay-E4 estimatedProcessingTime: - result: "30" + result: + "$serde_json::private::Number": "30" priority: - result: "\"normal\"" + result: normal ip1: id: ip1 input: ~ diff --git a/core/engine/tests/snapshots/engine__warehouse-storage-location_0.snap b/core/engine/tests/snapshots/engine__warehouse-storage-location_0.snap index 1ea410b5..999f76f0 100644 --- a/core/engine/tests/snapshots/engine__warehouse-storage-location_0.snap +++ b/core/engine/tests/snapshots/engine__warehouse-storage-location_0.snap @@ -126,13 +126,15 @@ trace: performance: "[perf]" traceData: allocatedLocation: - result: "\"prime-picking-area-pallet-rack-bottom\"" + result: prime-picking-area-pallet-rack-bottom pickingEfficiencyScore: - result: "7" + result: + "$serde_json::private::Number": "7" recommendedQuantity: - result: "1250" + result: + "$serde_json::private::Number": "1250" replenishmentFrequency: - result: "\"weekly\"" + result: weekly input: id: input input: ~ diff --git a/core/expression/src/vm/date/mod.rs b/core/expression/src/vm/date/mod.rs index 99355b75..858fad24 100644 --- a/core/expression/src/vm/date/mod.rs +++ b/core/expression/src/vm/date/mod.rs @@ -2,11 +2,12 @@ use crate::variable::DynamicVariable; pub(crate) use crate::vm::date::duration::Duration; pub(crate) use crate::vm::date::duration_unit::DurationUnit; use crate::Variable; -use chrono::{DateTime, SecondsFormat}; +use chrono::{DateTime, SecondsFormat, Utc}; use chrono_tz::Tz; use serde_json::Value; use std::any::Any; use std::fmt::{Display, Formatter}; +use std::sync::{LazyLock, RwLock}; // Duration is a modified copy of `humantime` mod duration; @@ -175,7 +176,7 @@ impl VmDate { } mod helper { - use crate::vm::date::{Duration, DurationUnit}; + use crate::vm::date::{utc_now, Duration, DurationUnit}; use crate::Variable; use chrono::{ DateTime, Datelike, Days, LocalResult, Month, Months, NaiveDate, NaiveDateTime, Offset, @@ -203,7 +204,7 @@ mod helper { } pub fn now_tz(tz: Tz) -> DateTime { - Utc::now().with_timezone(&tz) + utc_now().with_timezone(&tz) } pub fn parse_date(var: Variable, tz_opt: Option) -> Option> { @@ -480,3 +481,20 @@ impl dyn DynamicVariable { self.as_any().downcast_ref::() } } + +#[cfg(test)] +pub static UTC_OVERRIDE: LazyLock>>> = + LazyLock::new(|| RwLock::new(None)); + +pub(crate) fn utc_now() -> DateTime { + #[cfg(test)] + { + if let Ok(override_time) = UTC_OVERRIDE.read() { + if let Some(time) = *override_time { + return time; + } + } + } + + Utc::now() +} diff --git a/core/expression/src/vm/helpers.rs b/core/expression/src/vm/helpers.rs index c4fdc979..a58778ae 100644 --- a/core/expression/src/vm/helpers.rs +++ b/core/expression/src/vm/helpers.rs @@ -1,3 +1,4 @@ +use crate::vm::date::utc_now; use crate::vm::error::{VMError, VMResult}; use chrono::{ DateTime, Datelike, Days, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc, Weekday, @@ -15,7 +16,7 @@ static TIME_H: &str = "%H"; pub(crate) fn date_time(str: &str) -> VMResult { if str == "now" { - return Ok(Utc::now().naive_utc()); + return Ok(utc_now().naive_utc()); } NaiveDateTime::parse_from_str(str, DATE_TIME) @@ -27,7 +28,7 @@ pub(crate) fn date_time(str: &str) -> VMResult { } pub(crate) fn time(str: &str) -> VMResult { - let now = Utc::now(); + let now = utc_now(); if str == "now" { return Ok(now.naive_utc().time()); diff --git a/test-data/graphs/booking-fraud-detection.json b/test-data/graphs/booking-fraud-detection.json deleted file mode 100644 index b96072f7..00000000 --- a/test-data/graphs/booking-fraud-detection.json +++ /dev/null @@ -1,428 +0,0 @@ -{ - "tests": [ - { - "input": { - "booking": { - "payment_method": "prepaid_card", - "amount": 2500, - "ip_country": "US" - }, - "account": { - "country": "US", - "bookings_last_24h": 6 - } - }, - "output": { - "flags": { - "manual_review": true, - "requires_verification": true - } - } - } - ], - "nodes": [ - { - "type": "inputNode", - "content": { - "schema": "" - }, - "id": "ip1", - "name": "request", - "position": { - "x": 110, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "r1-1", - "i1-1": "'prepaid_card'", - "i1-2": "> 2000", - "o1-1": "40", - "o1-2": "'High-value prepaid card transaction'" - }, - { - "_id": "r1-2", - "i1-1": "'prepaid_card'", - "i1-2": "", - "o1-1": "20", - "o1-2": "'Prepaid card transaction'" - }, - { - "_id": "r1-3", - "i1-1": "'gift_card'", - "i1-2": "> 1000", - "o1-1": "30", - "o1-2": "'High-value gift card transaction'" - }, - { - "_id": "r1-4", - "i1-1": "'gift_card'", - "i1-2": "", - "o1-1": "15", - "o1-2": "'Gift card transaction'" - }, - { - "_id": "r1-5", - "i1-1": "'cryptocurrency'", - "i1-2": "", - "o1-1": "25", - "o1-2": "'Cryptocurrency transaction'" - }, - { - "_id": "r1-6", - "i1-1": "'credit_card'", - "i1-2": "> 3000", - "o1-1": "15", - "o1-2": "'High-value credit card transaction'" - }, - { - "_id": "r1-7", - "i1-1": "", - "i1-2": "", - "o1-1": "0", - "o1-2": "'Standard transaction'" - } - ], - "inputs": [ - { - "id": "i1-1", - "name": "Payment Method", - "field": "booking.payment_method" - }, - { - "id": "i1-2", - "name": "Transaction Amount", - "field": "booking.amount" - } - ], - "outputs": [ - { - "id": "o1-1", - "name": "Payment Risk Score", - "field": "risk.payment.score" - }, - { - "id": "o1-2", - "name": "Payment Risk Reason", - "field": "risk.payment.reason" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "dt1", - "name": "payment_risk", - "position": { - "x": 430, - "y": 16 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "r2-1", - "i2-1": "> 5", - "i2-2": "!= booking.ip_country", - "o2-1": "50", - "o2-2": "'Multiple bookings from different country'" - }, - { - "_id": "r2-2", - "i2-1": "> 5", - "i2-2": "", - "o2-1": "30", - "o2-2": "'Multiple rapid bookings'" - }, - { - "_id": "r2-3", - "i2-1": "> 3", - "i2-2": "!= booking.ip_country", - "o2-1": "35", - "o2-2": "'Several bookings from different country'" - }, - { - "_id": "r2-4", - "i2-1": "> 3", - "i2-2": "", - "o2-1": "20", - "o2-2": "'Several rapid bookings'" - }, - { - "_id": "r2-5", - "i2-1": "", - "i2-2": "!= booking.ip_country", - "o2-1": "25", - "o2-2": "'Booking from different country'" - }, - { - "_id": "r2-6", - "i2-1": "", - "i2-2": "", - "o2-1": "0", - "o2-2": "'Normal booking pattern'" - } - ], - "inputs": [ - { - "id": "i2-1", - "name": "Recent Bookings 24h", - "field": "account.bookings_last_24h" - }, - { - "id": "i2-2", - "name": "Account Country", - "field": "account.country" - } - ], - "outputs": [ - { - "id": "o2-1", - "name": "Pattern Risk Score", - "field": "risk.pattern.score" - }, - { - "id": "o2-2", - "name": "Pattern Risk Reason", - "field": "risk.pattern.reason" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "dt2", - "name": "pattern_risk", - "position": { - "x": 430, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "r3-1", - "i3-1": "< 30", - "o3-1": "40", - "o3-2": "'New account with significant transaction'" - }, - { - "_id": "r3-2", - "i3-1": "< 90", - "o3-1": "20", - "o3-2": "'Relatively new account'" - }, - { - "_id": "r3-3", - "i3-1": "> 1", - "o3-1": "15", - "o3-2": "'Previous chargeback history'" - }, - { - "_id": "r3-4", - "i3-1": "", - "o3-1": "0", - "o3-2": "'Normal account history'" - } - ], - "inputs": [ - { - "id": "i3-1", - "name": "Account Age (days)", - "field": "account.age_days" - } - ], - "outputs": [ - { - "id": "o3-1", - "name": "Account Risk Score", - "field": "risk.account.score" - }, - { - "id": "o3-2", - "name": "Account Risk Reason", - "field": "risk.account.reason" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "dt3", - "name": "account_risk", - "position": { - "x": 430, - "y": 212 - } - }, - { - "type": "expressionNode", - "content": { - "expressions": [ - { - "id": "e1-1", - "key": "total_risk_score", - "value": "sum(\n map(values(risk), #.score)\n)" - }, - { - "id": "e1-5", - "key": "risk_factors", - "value": "map(\n filter(values(risk), #.score > 0),\n #.reason\n)" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "ex1", - "name": "risk_calculation", - "position": { - "x": 750, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "42dc5a6d-6605-40b6-83b4-bad0bcf445c6", - "7385e66d-dc97-4048-a214-3f35d0029465": ">= 70", - "35a4cafc-e27c-4419-bfd3-b89a3dcddf46": "\"high\"" - }, - { - "_id": "c7910082-59fa-4aaf-b67e-5f807db68180", - "7385e66d-dc97-4048-a214-3f35d0029465": ">= 30", - "35a4cafc-e27c-4419-bfd3-b89a3dcddf46": "\"medium\"" - }, - { - "_id": "cea70345-a575-4c72-a81d-b2808f1193ff", - "7385e66d-dc97-4048-a214-3f35d0029465": "", - "35a4cafc-e27c-4419-bfd3-b89a3dcddf46": "\"low\"" - } - ], - "inputs": [ - { - "id": "7385e66d-dc97-4048-a214-3f35d0029465", - "name": "Total risk score", - "field": "total_risk_score" - } - ], - "outputs": [ - { - "id": "35a4cafc-e27c-4419-bfd3-b89a3dcddf46", - "name": "Risk level", - "field": "risk_level" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "9213dd68-a9f4-4b90-ada9-c7418d8b3c51", - "name": "risk_level", - "position": { - "x": 1070, - "y": 114 - } - }, - { - "type": "expressionNode", - "content": { - "expressions": [ - { - "id": "d58ad60e-a542-4213-919d-66db853847ef", - "key": "flags.requires_verification", - "value": "risk_level in [\"medium\", \"high\"]" - }, - { - "id": "898fd37d-5370-4e9b-afa7-e04628805b29", - "key": "flags.manual_review", - "value": "risk_level == \"high\"" - } - ], - "passThrough": false, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "e6dd7428-9ce6-4d8d-9a62-e38af18da14b", - "name": "flags", - "position": { - "x": 1390, - "y": 114 - } - } - ], - "edges": [ - { - "id": "ed1", - "sourceId": "ip1", - "targetId": "dt1", - "type": "edge" - }, - { - "id": "ed2", - "sourceId": "ip1", - "targetId": "dt2", - "type": "edge" - }, - { - "id": "ed3", - "sourceId": "ip1", - "targetId": "dt3", - "type": "edge" - }, - { - "id": "ed4", - "sourceId": "dt1", - "targetId": "ex1", - "type": "edge" - }, - { - "id": "ed5", - "sourceId": "dt2", - "targetId": "ex1", - "type": "edge" - }, - { - "id": "ed6", - "sourceId": "dt3", - "targetId": "ex1", - "type": "edge" - }, - { - "id": "018917a8-1af8-4de1-88e9-f7aa829006fc", - "sourceId": "ex1", - "type": "edge", - "targetId": "9213dd68-a9f4-4b90-ada9-c7418d8b3c51" - }, - { - "id": "c627b3e0-ed4f-4701-a10c-668c84a96e70", - "sourceId": "9213dd68-a9f4-4b90-ada9-c7418d8b3c51", - "type": "edge", - "targetId": "e6dd7428-9ce6-4d8d-9a62-e38af18da14b" - } - ] -} \ No newline at end of file diff --git a/test-data/graphs/clinical-trial-eligibility-screener.json b/test-data/graphs/clinical-trial-eligibility-screener.json deleted file mode 100644 index 805bb190..00000000 --- a/test-data/graphs/clinical-trial-eligibility-screener.json +++ /dev/null @@ -1,502 +0,0 @@ -{ - "tests": [ - { - "input": { - "patient": { - "id": "P67890", - "name": "John Smith", - "age": 68, - "diagnosis": "lung_cancer", - "diseaseStage": "IV", - "currentMedications": [ - "immunosuppressants", - "albuterol", - "omeprazole" - ], - "priorTreatments": 3, - "comorbidities": [ - "autoimmune_disease", - "COPD" - ], - "lastLabResults": { - "wbc": 3.8, - "hgb": 10.9, - "plt": 150, - "creatinine": 1.2 - } - } - }, - "output": { - "decisionSummary": "Patient is not eligible for clinical trial", - "eligibilityReasons": [ - { - "flag": false, - "reason": "Patient taking excluded medications" - }, - { - "flag": true, - "reason": "Age within eligible range" - }, - { - "flag": false, - "reason": "Excluded comorbidity present" - }, - { - "flag": false, - "reason": "Stage IV patients excluded from trial" - }, - { - "flag": true, - "reason": "Diagnosis matches trial criteria" - }, - { - "flag": false, - "reason": "Too many prior treatments" - } - ], - "failedCriteria": [ - "medication", - "comorbidity", - "stage", - "priorTreatment" - ], - "isEligible": false - } - } - ], - "nodes": [ - { - "type": "inputNode", - "content": { - "schema": "" - }, - "id": "inputNode", - "name": "patient", - "position": { - "x": 110, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "rule1", - "diagnosis": "'breast_cancer', 'lung_cancer', 'colorectal_cancer'", - "diagnosisFlag": "true", - "diagnosisReason": "'Diagnosis matches trial criteria'" - }, - { - "_id": "rule2", - "diagnosis": "", - "diagnosisFlag": "false", - "diagnosisReason": "'Diagnosis does not match trial criteria'" - } - ], - "inputs": [ - { - "id": "diagnosis", - "name": "Diagnosis", - "field": "patient.diagnosis" - } - ], - "outputs": [ - { - "id": "diagnosisFlag", - "name": "DiagnosisFlag", - "field": "eligibility.diagnosis.flag" - }, - { - "id": "diagnosisReason", - "name": "DiagnosisReason", - "field": "eligibility.diagnosis.reason" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "diagnosisEligibility", - "name": "diagnosisEligibility", - "position": { - "x": 430, - "y": -131 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "rule1", - "stage": "'I', 'II', 'III'", - "stageFlag": "true", - "stageReason": "'Disease stage matches trial criteria'" - }, - { - "_id": "rule2", - "stage": "'IV'", - "stageFlag": "false", - "stageReason": "'Stage IV patients excluded from trial'" - }, - { - "_id": "rule3", - "stage": "", - "stageFlag": "false", - "stageReason": "'Unknown or invalid disease stage'" - } - ], - "inputs": [ - { - "id": "stage", - "name": "Stage", - "field": "patient.diseaseStage" - } - ], - "outputs": [ - { - "id": "stageFlag", - "name": "StageFlag", - "field": "eligibility.stage.flag" - }, - { - "id": "stageReason", - "name": "StageReason", - "field": "eligibility.stage.reason" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "diseaseStageEligibility", - "name": "diseaseStageEligibility", - "position": { - "x": 430, - "y": -33 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "rule1", - "medications": "some($, # in ['immunosuppressants', 'anticancer_agents', 'corticosteroids'])", - "medicationFlag": "false", - "medicationReason": "'Patient taking excluded medications'" - }, - { - "_id": "rule2", - "medications": "", - "medicationFlag": "true", - "medicationReason": "'No conflicting medications'" - } - ], - "inputs": [ - { - "id": "medications", - "name": "Medications", - "field": "patient.currentMedications ?? []" - } - ], - "outputs": [ - { - "id": "medicationFlag", - "name": "MedicationFlag", - "field": "eligibility.medication.flag" - }, - { - "id": "medicationReason", - "name": "MedicationReason", - "field": "eligibility.medication.reason" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "medicationEligibility", - "name": "medicationEligibility", - "position": { - "x": 430, - "y": 65 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "rule1", - "age": ")18..75(", - "ageFlag": "false", - "ageReason": "'Age outside eligible range (18-75)'" - }, - { - "_id": "rule2", - "age": "", - "ageFlag": "true", - "ageReason": "'Age within eligible range'" - } - ], - "inputs": [ - { - "id": "age", - "name": "PatientAge", - "field": "patient.age" - } - ], - "outputs": [ - { - "id": "ageFlag", - "name": "AgeFlag", - "field": "eligibility.age.flag" - }, - { - "id": "ageReason", - "name": "AgeReason", - "field": "eligibility.age.reason" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "ageEligibility", - "name": "ageEligibility", - "position": { - "x": 430, - "y": 163 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "rule1", - "priorTreatments": "> 2", - "treatmentFlag": "false", - "treatmentReason": "'Too many prior treatments'" - }, - { - "_id": "rule2", - "priorTreatments": "<= 2", - "treatmentFlag": "true", - "treatmentReason": "'Acceptable number of prior treatments'" - }, - { - "_id": "rule3", - "priorTreatments": "", - "treatmentFlag": "true", - "treatmentReason": "'No prior treatments recorded'" - } - ], - "inputs": [ - { - "id": "priorTreatments", - "name": "PriorTreatments", - "field": "patient.priorTreatments" - } - ], - "outputs": [ - { - "id": "treatmentFlag", - "name": "TreatmentFlag", - "field": "eligibility.priorTreatment.flag" - }, - { - "id": "treatmentReason", - "name": "TreatmentReason", - "field": "eligibility.priorTreatment.reason" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "priorTreatmentEligibility", - "name": "priorTreatmentEligibility", - "position": { - "x": 430, - "y": 261 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "rule1", - "comorbidities": "some($, # in ['autoimmune_disease', 'heart_failure', 'uncontrolled_diabetes'])", - "comorbidityFlag": "false", - "comorbidityReason": "'Excluded comorbidity present'" - }, - { - "_id": "rule2", - "comorbidities": "", - "comorbidityFlag": "true", - "comorbidityReason": "'No exclusionary comorbidities'" - } - ], - "inputs": [ - { - "id": "comorbidities", - "name": "Comorbidities", - "field": "patient.comorbidities ?? []" - } - ], - "outputs": [ - { - "id": "comorbidityFlag", - "name": "ComorbidityFlag", - "field": "eligibility.comorbidity.flag" - }, - { - "id": "comorbidityReason", - "name": "ComorbidityReason", - "field": "eligibility.comorbidity.reason" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "comorbidityEligibility", - "name": "comorbidityEligibility", - "position": { - "x": 430, - "y": 359 - } - }, - { - "type": "expressionNode", - "content": { - "expressions": [ - { - "id": "expr1", - "key": "isEligible", - "value": "all(values(eligibility), #.flag)" - }, - { - "id": "expr2", - "key": "eligibilityReasons", - "value": "filter(values(eligibility), #.reason != null)" - }, - { - "id": "expr3", - "key": "decisionSummary", - "value": "$.isEligible ? 'Patient is eligible for clinical trial' : 'Patient is not eligible for clinical trial'" - }, - { - "id": "expr4", - "key": "failedCriteria", - "value": "filter(keys(eligibility), eligibility[#].flag == false)" - } - ], - "passThrough": false, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "eligibilitySummary", - "name": "eligibilitySummary", - "position": { - "x": 750, - "y": 114 - } - } - ], - "edges": [ - { - "id": "edge1", - "sourceId": "inputNode", - "targetId": "diagnosisEligibility", - "type": "edge" - }, - { - "id": "edge2", - "sourceId": "inputNode", - "targetId": "diseaseStageEligibility", - "type": "edge" - }, - { - "id": "edge3", - "sourceId": "inputNode", - "targetId": "medicationEligibility", - "type": "edge" - }, - { - "id": "edge4", - "sourceId": "inputNode", - "targetId": "ageEligibility", - "type": "edge" - }, - { - "id": "edge5", - "sourceId": "inputNode", - "targetId": "priorTreatmentEligibility", - "type": "edge" - }, - { - "id": "edge6", - "sourceId": "inputNode", - "targetId": "comorbidityEligibility", - "type": "edge" - }, - { - "id": "edge7", - "sourceId": "diagnosisEligibility", - "targetId": "eligibilitySummary", - "type": "edge" - }, - { - "id": "edge8", - "sourceId": "diseaseStageEligibility", - "targetId": "eligibilitySummary", - "type": "edge" - }, - { - "id": "edge9", - "sourceId": "medicationEligibility", - "targetId": "eligibilitySummary", - "type": "edge" - }, - { - "id": "edge10", - "sourceId": "ageEligibility", - "targetId": "eligibilitySummary", - "type": "edge" - }, - { - "id": "edge11", - "sourceId": "priorTreatmentEligibility", - "targetId": "eligibilitySummary", - "type": "edge" - }, - { - "id": "edge12", - "sourceId": "comorbidityEligibility", - "targetId": "eligibilitySummary", - "type": "edge" - } - ] -} \ No newline at end of file diff --git a/test-data/graphs/flight-ancillary-recommendations.json b/test-data/graphs/flight-ancillary-recommendations.json deleted file mode 100644 index 8d777732..00000000 --- a/test-data/graphs/flight-ancillary-recommendations.json +++ /dev/null @@ -1,436 +0,0 @@ -{ - "tests": [ - { - "input": { - "customerProfile": { - "id": "cust-12345", - "loyaltyTier": "gold", - "travelFrequency": "frequent", - "preferredLanguage": "en", - "preferredCurrency": "USD" - }, - "route": { - "origin": "JFK", - "destination": "international", - "flightDurationMinutes": 480, - "hasAirportLounge": true, - "departureTime": "2025-04-15T08:30:00Z", - "returnTime": "2025-04-22T15:45:00Z" - }, - "travelPurpose": "business", - "tripDetails": { - "passengers": 1, - "cabinClass": "economy", - "dateFlexibility": "fixed" - }, - "previousPurchases": [ - { - "bookingId": "bkg-9876", - "productType": "seat", - "purchaseDate": "2024-12-10T14:22:00Z", - "productDetails": { - "seatType": "extra_legroom", - "amount": 35 - } - }, - { - "bookingId": "bkg-8765", - "productType": "wifi", - "purchaseDate": "2024-11-05T09:15:00Z", - "productDetails": { - "packageType": "full_flight", - "amount": 19.99 - } - } - ] - }, - "output": { - "recommendations": [ - { - "priority": 5, - "productType": "lounge" - }, - { - "priority": 4, - "productType": "priority_boarding" - }, - { - "priority": 3, - "productType": "wifi" - }, - { - "priority": 4, - "productType": "lounge" - }, - { - "priority": 3, - "productType": "travel_insurance" - }, - { - "priority": 2, - "productType": "premium_meal" - }, - { - "priority": 4, - "productType": "fast_track_security" - } - ] - } - } - ], - "nodes": [ - { - "type": "inputNode", - "content": { - "schema": "" - }, - "id": "ip1", - "name": "request", - "position": { - "x": 110, - "y": 292.5 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "r1-1", - "i1-1": ">= 240", - "o1-1": "'long'" - }, - { - "_id": "r1-2", - "i1-1": ">= 120 and < 240", - "o1-1": "'medium'" - }, - { - "_id": "r1-3", - "i1-1": "< 120", - "o1-1": "'short'" - } - ], - "inputs": [ - { - "id": "i1-1", - "name": "Flight Duration Minutes", - "field": "route.flightDurationMinutes" - } - ], - "outputs": [ - { - "id": "o1-1", - "name": "Duration Category", - "field": "flightDurationCategory" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "dt1", - "name": "categorize_flight_duration", - "position": { - "x": 430, - "y": 292.5 - } - }, - { - "type": "expressionNode", - "content": { - "expressions": [ - { - "id": "e1-1", - "key": "isPremiumCustomer", - "value": "customerProfile.loyaltyTier == 'gold' or customerProfile.loyaltyTier == 'platinum'" - }, - { - "id": "e1-2", - "key": "hasBoughtBaggage", - "value": "some(previousPurchases ?? [], #.productType == 'baggage')" - }, - { - "id": "e1-3", - "key": "hasBoughtMeals", - "value": "some(previousPurchases ?? [], #.productType == 'meal')" - }, - { - "id": "e1-4", - "key": "hasBoughtSeats", - "value": "some(previousPurchases ?? [], #.productType == 'seat')" - }, - { - "id": "e1-5", - "key": "hasBoughtLounge", - "value": "some(previousPurchases ?? [], #.productType == 'lounge')" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "ex1", - "name": "calculate_customer_attributes", - "position": { - "x": 750, - "y": 292.5 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "collect", - "rules": [ - { - "_id": "r2-1", - "i2-1": "'business'", - "i2-2": "'long'", - "i2-3": "isPremiumCustomer", - "o2-1": "'lounge'", - "o2-2": "5" - }, - { - "_id": "r2-2", - "i2-1": "'business'", - "i2-2": "'medium', 'long'", - "i2-3": "", - "o2-1": "'priority_boarding'", - "o2-2": "4" - }, - { - "_id": "r2-3", - "i2-1": "'business'", - "i2-2": "", - "i2-3": "", - "o2-1": "'wifi'", - "o2-2": "3" - }, - { - "_id": "r2-4", - "i2-1": "'leisure'", - "i2-2": "'long'", - "i2-3": "", - "o2-1": "'extra_baggage'", - "o2-2": "5" - }, - { - "_id": "r2-5", - "i2-1": "'leisure'", - "i2-2": "'medium', 'long'", - "i2-3": "!hasBoughtMeals", - "o2-1": "'meal'", - "o2-2": "4" - }, - { - "_id": "r2-6", - "i2-1": "'leisure'", - "i2-2": "", - "i2-3": "!hasBoughtSeats", - "o2-1": "'seat_selection'", - "o2-2": "3" - }, - { - "_id": "r2-7", - "i2-1": "'family'", - "i2-2": "'medium', 'long'", - "i2-3": "", - "o2-1": "'family_seating'", - "o2-2": "5" - }, - { - "_id": "r2-8", - "i2-1": "'family'", - "i2-2": "", - "i2-3": "!hasBoughtBaggage", - "o2-1": "'extra_baggage'", - "o2-2": "4" - }, - { - "_id": "r2-9", - "i2-1": "'family'", - "i2-2": "'long'", - "i2-3": "", - "o2-1": "'entertainment_package'", - "o2-2": "3" - } - ], - "inputs": [ - { - "id": "i2-1", - "name": "Travel Purpose", - "field": "travelPurpose" - }, - { - "id": "i2-2", - "name": "Flight Duration", - "field": "flightDurationCategory" - }, - { - "id": "i2-3", - "name": "Customer Attributes", - "field": "" - } - ], - "outputs": [ - { - "id": "o2-1", - "name": "Product", - "field": "productType" - }, - { - "id": "o2-2", - "name": "Priority", - "field": "priority" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": "recommendations.base", - "executionMode": "single", - "passThorough": false - }, - "id": "dt2", - "name": "base_recommendations", - "position": { - "x": 1070, - "y": 292.5 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "collect", - "rules": [ - { - "_id": "r3-1", - "i3-1": "route.hasAirportLounge and !hasBoughtLounge", - "i3-2": "isPremiumCustomer", - "o3-1": "'lounge'", - "o3-2": "4" - }, - { - "_id": "r3-2", - "i3-1": "route.destination == 'international'", - "i3-2": "", - "o3-1": "'travel_insurance'", - "o3-2": "3" - }, - { - "_id": "r3-3", - "i3-1": "flightDurationCategory == 'long' and !hasBoughtMeals", - "i3-2": "", - "o3-1": "'premium_meal'", - "o3-2": "2" - }, - { - "_id": "r3-4", - "i3-1": "customerProfile.travelFrequency == 'frequent' and travelPurpose == 'business'", - "i3-2": "", - "o3-1": "'fast_track_security'", - "o3-2": "4" - }, - { - "_id": "r3-5", - "i3-1": "route.destination == 'beach' or route.destination == 'resort'", - "i3-2": "travelPurpose == 'leisure'", - "o3-1": "'excursion_package'", - "o3-2": "3" - } - ], - "inputs": [ - { - "id": "i3-1", - "name": "Route Attributes", - "field": "" - }, - { - "id": "i3-2", - "name": "Customer Context", - "field": "" - } - ], - "outputs": [ - { - "id": "o3-1", - "name": "Additional Product", - "field": "productType" - }, - { - "id": "o3-2", - "name": "Priority", - "field": "priority" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": "recommendations.additional", - "executionMode": "single", - "passThorough": false - }, - "id": "dt3", - "name": "additional_recommendations", - "position": { - "x": 1390, - "y": 292.5 - } - }, - { - "type": "expressionNode", - "content": { - "expressions": [ - { - "id": "0a0fbafe-0a16-445a-99f8-c8b4341ef370", - "key": "recommendations", - "value": "flatten(values(recommendations))" - } - ], - "passThrough": false, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "8cb0ce16-c426-4988-b39f-d122499bc1fd", - "name": "join_recommendations", - "position": { - "x": 1710, - "y": 292.5 - } - } - ], - "edges": [ - { - "id": "ed1", - "sourceId": "ip1", - "targetId": "dt1", - "type": "edge" - }, - { - "id": "ed2", - "sourceId": "dt1", - "targetId": "ex1", - "type": "edge" - }, - { - "id": "ed3", - "sourceId": "ex1", - "targetId": "dt2", - "type": "edge" - }, - { - "id": "ed4", - "sourceId": "dt2", - "targetId": "dt3", - "type": "edge" - }, - { - "id": "d0ef3f95-c4cf-4311-8ae0-6d2fc9771730", - "sourceId": "dt3", - "type": "edge", - "targetId": "8cb0ce16-c426-4988-b39f-d122499bc1fd" - } - ] -} \ No newline at end of file diff --git a/test-data/graphs/marketplace-seller-grading-system.json b/test-data/graphs/marketplace-seller-grading-system.json deleted file mode 100644 index 982bc92a..00000000 --- a/test-data/graphs/marketplace-seller-grading-system.json +++ /dev/null @@ -1,436 +0,0 @@ -{ - "tests": [ - { - "input": { - "metrics": { - "onTimeDeliveryRate": 96.5, - "customerSatisfaction": 4.7, - "inventoryAccuracy": 97.2, - "policyCompliance": 94.8 - }, - "sellerInfo": { - "id": "S12345", - "name": "Global Gadgets Store", - "monthsActive": 18 - } - }, - "output": { - "grade": "B", - "recommendedAction": "Eligible for featured seller status", - "status": "Good" - } - } - ], - "nodes": [ - { - "type": "inputNode", - "content": { - "schema": "" - }, - "id": "ip1", - "name": "request", - "position": { - "x": 110, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "r1-1", - "i1-1": ">= 98", - "o1-1": "5" - }, - { - "_id": "r1-2", - "i1-1": ">= 95", - "o1-1": "4" - }, - { - "_id": "r1-3", - "i1-1": ">= 90", - "o1-1": "3" - }, - { - "_id": "r1-4", - "i1-1": ">= 85", - "o1-1": "2" - }, - { - "_id": "r1-5", - "i1-1": "", - "o1-1": "1" - } - ], - "inputs": [ - { - "id": "i1-1", - "name": "On-Time Delivery Rate", - "field": "metrics.onTimeDeliveryRate" - } - ], - "outputs": [ - { - "id": "o1-1", - "name": "Score", - "field": "scores.delivery" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "dt1", - "name": "evaluate_delivery", - "position": { - "x": 430, - "y": -33 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "r2-1", - "i2-1": ">= 4.8", - "o2-1": "5" - }, - { - "_id": "r2-2", - "i2-1": ">= 4.5", - "o2-1": "4" - }, - { - "_id": "r2-3", - "i2-1": ">= 4.0", - "o2-1": "3" - }, - { - "_id": "r2-4", - "i2-1": ">= 3.5", - "o2-1": "2" - }, - { - "_id": "r2-5", - "i2-1": "", - "o2-1": "1" - } - ], - "inputs": [ - { - "id": "i2-1", - "name": "Customer Satisfaction", - "field": "metrics.customerSatisfaction" - } - ], - "outputs": [ - { - "id": "o2-1", - "name": "Score", - "field": "scores.customerSatisfaction" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "dt2", - "name": "evaluate_satisfaction", - "position": { - "x": 430, - "y": 65 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "r3-1", - "i3-1": ">= 99", - "o3-1": "5" - }, - { - "_id": "r3-2", - "i3-1": ">= 95", - "o3-1": "4" - }, - { - "_id": "r3-3", - "i3-1": ">= 90", - "o3-1": "3" - }, - { - "_id": "r3-4", - "i3-1": ">= 85", - "o3-1": "2" - }, - { - "_id": "r3-5", - "i3-1": "", - "o3-1": "1" - } - ], - "inputs": [ - { - "id": "i3-1", - "name": "Inventory Accuracy", - "field": "metrics.inventoryAccuracy" - } - ], - "outputs": [ - { - "id": "o3-1", - "name": "Score", - "field": "scores.inventory" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "dt3", - "name": "evaluate_inventory", - "position": { - "x": 430, - "y": 163 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "r4-1", - "i4-1": ">= 98", - "o4-1": "5" - }, - { - "_id": "r4-2", - "i4-1": ">= 95", - "o4-1": "4" - }, - { - "_id": "r4-3", - "i4-1": ">= 90", - "o4-1": "3" - }, - { - "_id": "r4-4", - "i4-1": ">= 85", - "o4-1": "2" - }, - { - "_id": "r4-5", - "i4-1": "", - "o4-1": "1" - } - ], - "inputs": [ - { - "id": "i4-1", - "name": "Policy Compliance", - "field": "metrics.policyCompliance" - } - ], - "outputs": [ - { - "id": "o4-1", - "name": "Score", - "field": "scores.compliance" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "dt4", - "name": "evaluate_compliance", - "position": { - "x": 430, - "y": 261 - } - }, - { - "type": "expressionNode", - "content": { - "expressions": [ - { - "id": "e1-5", - "key": "averageScore", - "value": "avg(values(scores))" - }, - { - "id": "e1-6", - "key": "strengths", - "value": "filter(keys(scores), scores[#] >= 4)" - }, - { - "id": "e1-7", - "key": "improvements", - "value": "filter(keys(scores), scores[#] <= 2)" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": "scores", - "executionMode": "single" - }, - "id": "ex1", - "name": "aggregate_scores", - "position": { - "x": 750, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "r5-1", - "i5-1": ">= 4.5", - "o5-1": "'A'", - "o5-2": "'Outstanding'", - "o5-3": "'Eligible for premium seller status'" - }, - { - "_id": "r5-2", - "i5-1": ">= 3.5", - "o5-1": "'B'", - "o5-2": "'Good'", - "o5-3": "'Eligible for featured seller status'" - }, - { - "_id": "r5-3", - "i5-1": ">= 2.5", - "o5-1": "'C'", - "o5-2": "'Satisfactory'", - "o5-3": "'Standard seller privileges'" - }, - { - "_id": "r5-4", - "i5-1": ">= 1.5", - "o5-1": "'D'", - "o5-2": "'Needs Improvement'", - "o5-3": "'Performance improvement plan required'" - }, - { - "_id": "r5-5", - "i5-1": "", - "o5-1": "'F'", - "o5-2": "'Poor'", - "o5-3": "'Account review required'" - } - ], - "inputs": [ - { - "id": "i5-1", - "name": "Average Score", - "field": "scores.averageScore" - } - ], - "outputs": [ - { - "id": "o5-1", - "name": "Grade", - "field": "grade" - }, - { - "id": "o5-2", - "name": "Status", - "field": "status" - }, - { - "id": "o5-3", - "name": "Action", - "field": "recommendedAction" - } - ], - "passThrough": false, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "dt5", - "name": "calculate_final_grade", - "position": { - "x": 1070, - "y": 114 - } - } - ], - "edges": [ - { - "id": "ed1", - "sourceId": "ip1", - "targetId": "dt1", - "type": "edge" - }, - { - "id": "ed2", - "sourceId": "ip1", - "targetId": "dt2", - "type": "edge" - }, - { - "id": "ed3", - "sourceId": "ip1", - "targetId": "dt3", - "type": "edge" - }, - { - "id": "ed4", - "sourceId": "ip1", - "targetId": "dt4", - "type": "edge" - }, - { - "id": "ed5", - "sourceId": "dt1", - "targetId": "ex1", - "type": "edge" - }, - { - "id": "ed6", - "sourceId": "dt2", - "targetId": "ex1", - "type": "edge" - }, - { - "id": "ed7", - "sourceId": "dt3", - "targetId": "ex1", - "type": "edge" - }, - { - "id": "ed8", - "sourceId": "dt4", - "targetId": "ex1", - "type": "edge" - }, - { - "id": "ed9", - "sourceId": "ex1", - "targetId": "dt5", - "type": "edge" - } - ] -} \ No newline at end of file diff --git a/test-data/graphs/medical-appointment-priority-system.json b/test-data/graphs/medical-appointment-priority-system.json deleted file mode 100644 index be60af08..00000000 --- a/test-data/graphs/medical-appointment-priority-system.json +++ /dev/null @@ -1,446 +0,0 @@ -{ - "tests": [ - { - "input": { - "patient": { - "age": 72, - "hasChronicCondition": true, - "immunocompromised": false, - "recentHospitalization": true - }, - "appointment": { - "conditionSeverity": "moderate", - "daysWaiting": 12, - "isFollowUp": true - } - }, - "output": { - "priorityFactors": [ - "Moderate condition with follow-up", - "Moderate wait time (8-14 days)", - "Age over 65", - "Chronic condition", - "Recent hospitalization" - ], - "result": { - "priority": "HIGH", - "recommendation": "Schedule within 24-48 hours" - }, - "scores": { - "conditionSeverity": 20, - "riskFactors": 40, - "waitTime": 10 - }, - "totalScore": 70 - } - } - ], - "nodes": [ - { - "id": "inputNode", - "name": "request", - "type": "inputNode", - "content": { - "schema": "{\n \"type\": \"object\",\n \"properties\": {\n \"patient\": {\n \"type\": \"object\",\n \"properties\": {\n \"age\": {\n \"type\": \"number\"\n },\n \"hasChronicCondition\": {\n \"type\": \"boolean\"\n },\n \"immunocompromised\": {\n \"type\": \"boolean\"\n },\n \"recentHospitalization\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"appointment\": {\n \"type\": \"object\",\n \"properties\": {\n \"conditionSeverity\": {\n \"type\": \"string\",\n \"enum\": [\"mild\", \"moderate\", \"severe\", \"critical\"]\n },\n \"daysWaiting\": {\n \"type\": \"number\"\n },\n \"isFollowUp\": {\n \"type\": \"boolean\"\n }\n }\n }\n }\n}" - }, - "position": { - "x": 110, - "y": 114 - } - }, - { - "id": "riskFactorScoreNode", - "name": "calculateRiskFactorScore", - "type": "decisionTableNode", - "content": { - "rules": [ - { - "_id": "risk1", - "i1-1": "patient.age > 65", - "o1-1": "10", - "o1-2": "'Age over 65'", - "_description": "" - }, - { - "_id": "risk2", - "i1-1": "patient.hasChronicCondition", - "o1-1": "15", - "o1-2": "'Chronic condition'", - "_description": "" - }, - { - "_id": "risk3", - "i1-1": "patient.immunocompromised", - "o1-1": "20", - "o1-2": "'Immunocompromised'", - "_description": "" - }, - { - "_id": "risk4", - "i1-1": "patient.recentHospitalization", - "o1-1": "15", - "o1-2": "'Recent hospitalization'", - "_description": "" - } - ], - "inputs": [ - { - "id": "i1-1", - "name": "Condition" - } - ], - "outputs": [ - { - "id": "o1-1", - "name": "Score", - "field": "score" - }, - { - "id": "o1-2", - "name": "Reason", - "field": "message" - } - ], - "hitPolicy": "collect", - "inputField": null, - "outputPath": "riskFactors", - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 430, - "y": 114 - } - }, - { - "id": "conditionSeverityNode", - "name": "evaluateConditionSeverity", - "type": "decisionTableNode", - "content": { - "rules": [ - { - "_id": "severity1", - "i2-1": "'critical'", - "i2-2": "", - "o2-1": "50", - "o2-2": "'Critical condition'" - }, - { - "_id": "severity2", - "i2-1": "'severe'", - "i2-2": "", - "o2-1": "30", - "o2-2": "'Severe condition'" - }, - { - "_id": "severity3", - "i2-1": "'moderate'", - "i2-2": "true", - "o2-1": "20", - "o2-2": "'Moderate condition with follow-up'" - }, - { - "_id": "severity4", - "i2-1": "'moderate'", - "i2-2": "false", - "o2-1": "15", - "o2-2": "'Moderate condition'" - }, - { - "_id": "severity5", - "i2-1": "'mild'", - "i2-2": "true", - "o2-1": "10", - "o2-2": "'Mild condition with follow-up'" - }, - { - "_id": "severity6", - "i2-1": "'mild'", - "i2-2": "false", - "o2-1": "5", - "o2-2": "'Mild condition'" - } - ], - "inputs": [ - { - "id": "i2-1", - "name": "Condition Severity", - "field": "appointment.conditionSeverity" - }, - { - "id": "i2-2", - "name": "Is Follow Up", - "field": "appointment.isFollowUp" - } - ], - "outputs": [ - { - "id": "o2-1", - "name": "Score", - "field": "scores.conditionSeverity" - }, - { - "id": "o2-2", - "name": "Reason", - "field": "reasons.conditionSeverity" - } - ], - "hitPolicy": "first", - "inputField": null, - "outputPath": null, - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 1070, - "y": 114 - } - }, - { - "id": "waitTimeScoreNode", - "name": "calculateWaitTimeScore", - "type": "decisionTableNode", - "content": { - "rules": [ - { - "_id": "wait1", - "i3-1": "> 30", - "o3-1": "25", - "o3-2": "'Excessive wait time (> 30 days)'" - }, - { - "_id": "wait2", - "i3-1": "> 14", - "o3-1": "15", - "o3-2": "'Long wait time (15-30 days)'" - }, - { - "_id": "wait3", - "i3-1": "> 7", - "o3-1": "10", - "o3-2": "'Moderate wait time (8-14 days)'" - }, - { - "_id": "wait4", - "i3-1": "> 3", - "o3-1": "5", - "o3-2": "'Short wait time (4-7 days)'" - }, - { - "_id": "wait5", - "i3-1": "", - "o3-1": "0", - "o3-2": "'Minimal wait time (0-3 days)'" - } - ], - "inputs": [ - { - "id": "i3-1", - "name": "Days Waiting", - "field": "appointment.daysWaiting" - } - ], - "outputs": [ - { - "id": "o3-1", - "name": "Score", - "field": "scores.waitTime" - }, - { - "id": "o3-2", - "name": "Reason", - "field": "reasons.waitTime" - } - ], - "hitPolicy": "first", - "inputField": null, - "outputPath": null, - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 1390, - "y": 114 - } - }, - { - "id": "totalPriorityScoreNode", - "name": "calculateTotalPriorityScore", - "type": "expressionNode", - "content": { - "inputField": null, - "outputPath": null, - "expressions": [ - { - "id": "expr1", - "key": "totalScore", - "value": "sum(values(scores))" - }, - { - "id": "expr2", - "key": "priorityFactors", - "value": "flatten(values(reasons))" - }, - { - "id": "f7a526e0-582e-4717-b2c1-8b9df0c504d8", - "key": "reasons", - "value": "null" - }, - { - "id": "b4e49a47-a434-484d-807a-739c32a616db", - "key": "patient", - "value": "null" - }, - { - "id": "dba4d54a-67be-4cca-9258-07b52c76fb61", - "key": "appointment", - "value": "null" - } - ], - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 1710, - "y": 114 - } - }, - { - "id": "priorityAssignmentNode", - "name": "assignPriorityLevel", - "type": "decisionTableNode", - "content": { - "rules": [ - { - "_id": "priority1", - "i4-1": ">= 85", - "o4-1": "'URGENT'", - "o4-2": "'Schedule immediately'" - }, - { - "_id": "priority2", - "i4-1": ">= 60", - "o4-1": "'HIGH'", - "o4-2": "'Schedule within 24-48 hours'" - }, - { - "_id": "priority3", - "i4-1": ">= 40", - "o4-1": "'MEDIUM'", - "o4-2": "'Schedule within 1 week'" - }, - { - "_id": "priority4", - "i4-1": ">= 20", - "o4-1": "'STANDARD'", - "o4-2": "'Schedule within 2 weeks'" - }, - { - "_id": "priority5", - "i4-1": "", - "o4-1": "'LOW'", - "o4-2": "'Schedule as available'" - } - ], - "inputs": [ - { - "id": "i4-1", - "name": "Total Score", - "field": "totalScore" - } - ], - "outputs": [ - { - "id": "o4-1", - "name": "Priority", - "field": "result.priority" - }, - { - "id": "o4-2", - "name": "Recommendation", - "field": "result.recommendation" - } - ], - "hitPolicy": "first", - "inputField": null, - "outputPath": null, - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 2030, - "y": 114 - } - }, - { - "id": "02b0be40-dfe0-4a11-a9a4-17f66823f0c2", - "name": "riskFactorSummary", - "type": "expressionNode", - "content": { - "inputField": null, - "outputPath": null, - "expressions": [ - { - "id": "dc9c736d-00fb-4a40-b9ec-59012e9cbbad", - "key": "scores.riskFactors", - "value": "sum(map(riskFactors, #.score))" - }, - { - "id": "26479ea2-761e-4c16-975d-b0d26f4e8f8f", - "key": "reasons.riskFactors", - "value": "map(riskFactors, #.message)" - }, - { - "id": "50d71c19-5c0a-4957-8ec0-c45309ad4f45", - "key": "riskFactors", - "value": "null" - } - ], - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 750, - "y": 114 - } - } - ], - "edges": [ - { - "id": "edge1", - "type": "edge", - "sourceId": "inputNode", - "targetId": "riskFactorScoreNode" - }, - { - "id": "edge3", - "type": "edge", - "sourceId": "conditionSeverityNode", - "targetId": "waitTimeScoreNode" - }, - { - "id": "edge4", - "type": "edge", - "sourceId": "waitTimeScoreNode", - "targetId": "totalPriorityScoreNode" - }, - { - "id": "edge5", - "type": "edge", - "sourceId": "totalPriorityScoreNode", - "targetId": "priorityAssignmentNode" - }, - { - "id": "607f2b6e-b5ca-4cdd-8e59-d1539f9dda2b", - "type": "edge", - "sourceId": "riskFactorScoreNode", - "targetId": "02b0be40-dfe0-4a11-a9a4-17f66823f0c2" - }, - { - "id": "e857ae81-6c47-4630-8706-c9eba58170ff", - "type": "edge", - "sourceId": "02b0be40-dfe0-4a11-a9a4-17f66823f0c2", - "targetId": "conditionSeverityNode" - } - ] -} \ No newline at end of file diff --git a/test-data/graphs/patient-triage-system.json b/test-data/graphs/patient-triage-system.json deleted file mode 100644 index 28cc1a05..00000000 --- a/test-data/graphs/patient-triage-system.json +++ /dev/null @@ -1,406 +0,0 @@ -{ - "tests": [ - { - "input": { - "vitals": { - "temperature": 38.7, - "heartRate": 115, - "respiratoryRate": 24, - "systolicBP": 165, - "oxygenSaturation": 94 - }, - "symptoms": [ - "moderate pain", - "fever", - "dizziness" - ], - "chiefComplaint": "fracture" - }, - "output": { - "highestFlag": "orange", - "maxWaitTimeMinutes": 10, - "priorityLevel": "Level 2 - Very Urgent" - } - } - ], - "nodes": [ - { - "type": "inputNode", - "content": { - "schema": "" - }, - "id": "input", - "name": "request", - "position": { - "x": 110, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "vs1", - "i1": "> 39.5", - "i2": ")40..160(", - "i3": ")8..30(", - "i4": ")80..200(", - "i5": "< 90", - "o1": "30", - "o2": "'red'" - }, - { - "_id": "vs2", - "i1": "> 38.5", - "i2": ")50..150(", - "i3": ")10..25(", - "i4": ")90..180(", - "i5": "< 93", - "o1": "20", - "o2": "'orange'" - }, - { - "_id": "vs3", - "i1": "> 38.0", - "i2": ")55..140(", - "i3": ")12..22(", - "i4": ")100..170(", - "i5": "< 95", - "o1": "10", - "o2": "'yellow'" - }, - { - "_id": "vs4", - "i1": "", - "i2": "", - "i3": "", - "i4": "", - "i5": "", - "o1": "0", - "o2": "'green'" - } - ], - "inputs": [ - { - "id": "i1", - "name": "Temperature (°C)", - "field": "vitals.temperature" - }, - { - "id": "i2", - "name": "Heart Rate (bpm)", - "field": "vitals.heartRate" - }, - { - "id": "i3", - "name": "Respiratory Rate (bpm)", - "field": "vitals.respiratoryRate" - }, - { - "id": "i4", - "name": "Systolic BP (mmHg)", - "field": "vitals.systolicBP" - }, - { - "id": "i5", - "name": "O2 Saturation (%)", - "field": "vitals.oxygenSaturation" - } - ], - "outputs": [ - { - "id": "o1", - "name": "Score", - "field": "scores.vitalScore" - }, - { - "id": "o2", - "name": "Flag", - "field": "flags.vitalFlag" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "vitalSigns", - "name": "vital_signs_assessment", - "position": { - "x": 430, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "sym1", - "i1": "some(symptoms, # in [\"severe pain\", \"chest pain\", \"difficulty breathing\", \"unconscious\", \"unresponsive\", \"active bleeding\"])", - "o1": "30", - "o2": "'red'" - }, - { - "_id": "sym2", - "i1": "some(symptoms, # in [\"moderate pain\", \"vomiting\", \"dehydration\", \"fever\", \"dizziness\", \"head injury\"])", - "o1": "20", - "o2": "'orange'" - }, - { - "_id": "sym3", - "i1": "some(symptoms, # in [\"mild pain\", \"nausea\", \"minor injury\", \"rash\", \"cough\"])", - "o1": "10", - "o2": "'yellow'" - }, - { - "_id": "sym4", - "i1": "", - "o1": "0", - "o2": "'green'" - } - ], - "inputs": [ - { - "id": "i1", - "name": "Expression" - } - ], - "outputs": [ - { - "id": "o1", - "name": "Score", - "field": "scores.symptomScore" - }, - { - "id": "o2", - "name": "Flag", - "field": "flags.symptomFlag" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "symptoms", - "name": "symptom_assessment", - "position": { - "x": 750, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "cc1", - "i1": "\"stroke\", \"heart attack\", \"cardiac arrest\", \"trauma\", \"anaphylaxis\", \"overdose\", \"seizure\"", - "o1": "40", - "o2": "'red'" - }, - { - "_id": "cc2", - "i1": "\"fracture\", \"deep cut\", \"burn\", \"allergic reaction\", \"infection\", \"pregnancy complication\"", - "o1": "20", - "o2": "'orange'" - }, - { - "_id": "cc3", - "i1": "\"sprain\", \"minor cut\", \"cold\", \"flu\", \"ear pain\", \"medication refill\"", - "o1": "10", - "o2": "'yellow'" - }, - { - "_id": "cc4", - "i1": "", - "o1": "0", - "o2": "'green'" - } - ], - "inputs": [ - { - "id": "i1", - "name": "Chief Complaint", - "field": "chiefComplaint" - } - ], - "outputs": [ - { - "id": "o1", - "name": "Score", - "field": "scores.complaintScore" - }, - { - "id": "o2", - "name": "Flag", - "field": "flags.complaintFlag" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": null, - "executionMode": "single", - "passThorough": false - }, - "id": "chiefComplaint", - "name": "chief_complaint_assessment", - "position": { - "x": 1070, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "first", - "rules": [ - { - "_id": "cp1", - "i1": "contains($, 'red')", - "i2": ">= 60", - "o1": "'Level 1 - Immediate'", - "o2": "0", - "o3": "'red'" - }, - { - "_id": "cp2", - "i1": "contains($, 'red')", - "i2": ">= 40", - "o1": "'Level 2 - Very Urgent'", - "o2": "10", - "o3": "'red'" - }, - { - "_id": "cp3", - "i1": "contains($, 'orange')", - "i2": ">= 40", - "o1": "'Level 2 - Very Urgent'", - "o2": "10", - "o3": "'orange'" - }, - { - "_id": "cp4", - "i1": "", - "i2": ">= 40", - "o1": "'Level 2 - Very Urgent'", - "o2": "10", - "o3": "'orange'" - }, - { - "_id": "cp5", - "i1": "contains($, 'orange')", - "i2": ">= 20", - "o1": "'Level 3 - Urgent'", - "o2": "30", - "o3": "'orange'" - }, - { - "_id": "cp6", - "i1": "", - "i2": ">= 20", - "o1": "'Level 3 - Urgent'", - "o2": "30", - "o3": "'yellow'" - }, - { - "_id": "cp7", - "i1": "contains($, 'yellow')", - "i2": ">= 10", - "o1": "'Level 4 - Standard'", - "o2": "60", - "o3": "'yellow'" - }, - { - "_id": "cp8", - "i1": "", - "i2": ">= 10", - "o1": "'Level 4 - Standard'", - "o2": "60", - "o3": "'green'" - }, - { - "_id": "cp9", - "i1": "", - "i2": "", - "o1": "'Level 5 - Non-Urgent'", - "o2": "120", - "o3": "'green'" - } - ], - "inputs": [ - { - "id": "i1", - "name": "All flags", - "field": "values(flags)" - }, - { - "id": "i2", - "name": "Total Score", - "field": "scores.vitalScore + scores.symptomScore + scores.complaintScore" - } - ], - "outputs": [ - { - "id": "o1", - "name": "Priority Level", - "field": "priorityLevel" - }, - { - "id": "o2", - "name": "Max Wait Time (minutes)", - "field": "maxWaitTimeMinutes" - }, - { - "id": "o3", - "name": "Highest Flag", - "field": "highestFlag" - } - ], - "passThrough": false, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "calculatePriority", - "name": "calculate_priority_level", - "position": { - "x": 1390, - "y": 114 - } - } - ], - "edges": [ - { - "id": "edge1", - "sourceId": "input", - "targetId": "vitalSigns", - "type": "edge" - }, - { - "id": "edge2", - "sourceId": "vitalSigns", - "targetId": "symptoms", - "type": "edge" - }, - { - "id": "edge3", - "sourceId": "symptoms", - "targetId": "chiefComplaint", - "type": "edge" - }, - { - "id": "edge4", - "sourceId": "chiefComplaint", - "targetId": "calculatePriority", - "type": "edge" - } - ] -} \ No newline at end of file diff --git a/test-data/graphs/portfolio-risk-monitor.json b/test-data/graphs/portfolio-risk-monitor.json deleted file mode 100644 index a5ac9ad8..00000000 --- a/test-data/graphs/portfolio-risk-monitor.json +++ /dev/null @@ -1,588 +0,0 @@ -{ - "tests": [ - { - "input": { - "customer": { - "id": "cust-78945", - "name": "John Smith", - "riskTolerance": "moderate", - "investmentHorizon": "long-term", - "preferences": { - "allowAutomaticAdjustments": true, - "alertThreshold": "moderate", - "communicationPreference": "email" - } - }, - "portfolio": { - "id": "port-12345", - "name": "Retirement Portfolio", - "totalValue": 750000, - "creationDate": "2019-05-12", - "lastRebalance": 95, - "volatility": 22.5, - "highRiskPercentage": 35, - "currentAllocation": { - "equity": 65, - "bonds": 25, - "cash": 10 - }, - "targetAllocation": { - "equity": 60, - "bonds": 35, - "cash": 5 - }, - "holdings": [ - { - "symbol": "VTI", - "category": "equity", - "percentage": 30, - "value": 225000 - }, - { - "symbol": "VXUS", - "category": "equity", - "percentage": 20, - "value": 150000 - }, - { - "symbol": "VGT", - "category": "equity", - "percentage": 15, - "value": 112500 - }, - { - "symbol": "BND", - "category": "bonds", - "percentage": 25, - "value": 187500 - }, - { - "symbol": "CASH", - "category": "cash", - "percentage": 10, - "value": 75000 - } - ] - }, - "market": { - "volatilityIndex": 28.5, - "trendPercentage": -12.5, - "interestRate": 3.75, - "sectorPerformance": { - "technology": -15.2, - "healthcare": -5.1, - "financials": -18.4, - "consumerStaples": -3.2, - "utilities": 1.5 - }, - "economicIndicators": { - "gdpGrowth": 0.8, - "inflation": 4.2, - "unemploymentRate": 4.1 - } - } - }, - "output": { - "action": "rebalance", - "outcome": { - "riskScore": 0.53, - "status": "rebalance_suggested", - "timestamp": "2025-08-19T16:55:02.078Z" - }, - "rebalanceDetails": { - "currentAllocation": { - "bonds": 25, - "cash": 10, - "equity": 65 - }, - "customerId": "cust-78945", - "date": "2025-08-19", - "driftPercentage": "5.0", - "message": "Rebalancing recommended: Portfolio has drifted 5.0% from target allocation.", - "portfolioId": "port-12345", - "riskCategory": "high", - "riskScore": 0.53, - "suggestedChanges": { - "bonds": 10, - "cash": -5, - "equity": -5 - }, - "targetAllocation": { - "bonds": 35, - "cash": 5, - "equity": 60 - } - } - } - } - ], - "nodes": [ - { - "id": "inputNode", - "name": "request", - "type": "inputNode", - "content": { - "schema": "" - }, - "position": { - "x": 110, - "y": 193.5 - } - }, - { - "id": "marketConditionsTable", - "name": "marketConditionsAssessment", - "type": "decisionTableNode", - "content": { - "rules": [ - { - "_id": "rule1", - "i1-1": "> 30", - "i1-2": "< -15", - "o1-1": "'severe'", - "o1-2": "0.8", - "o1-3": "'Highly volatile market with significant downward trend'" - }, - { - "_id": "rule2", - "i1-1": "> 25", - "i1-2": "< -10", - "o1-1": "'high'", - "o1-2": "0.7", - "o1-3": "'Elevated volatility with substantial market decline'" - }, - { - "_id": "rule3", - "i1-1": "> 20", - "i1-2": "< -5", - "o1-1": "'moderate'", - "o1-2": "0.5", - "o1-3": "'Increased volatility with market decline'" - }, - { - "_id": "rule4", - "i1-1": "> 25", - "i1-2": "> 5", - "o1-1": "'neutral'", - "o1-2": "0.3", - "o1-3": "'High volatility but positive market trend'" - }, - { - "_id": "rule5", - "i1-1": "> 15", - "i1-2": "", - "o1-1": "'elevated'", - "o1-2": "0.4", - "o1-3": "'Elevated market volatility'" - }, - { - "_id": "rule6", - "i1-1": "", - "i1-2": "< -10", - "o1-1": "'negative'", - "o1-2": "0.6", - "o1-3": "'Significant market decline'" - }, - { - "_id": "rule7", - "i1-1": "", - "i1-2": "", - "o1-1": "'normal'", - "o1-2": "0.2", - "o1-3": "'Normal market conditions'" - } - ], - "inputs": [ - { - "id": "i1-1", - "name": "Market Volatility Index", - "field": "market.volatilityIndex" - }, - { - "id": "i1-2", - "name": "Market Trend Percent", - "field": "market.trendPercentage" - } - ], - "outputs": [ - { - "id": "o1-1", - "name": "Market Condition", - "field": "assessment.marketCondition" - }, - { - "id": "o1-2", - "name": "Market Risk Factor", - "field": "assessment.marketRiskFactor" - }, - { - "id": "o1-3", - "name": "Market Assessment", - "field": "assessment.marketAssessment" - } - ], - "hitPolicy": "first", - "inputField": null, - "outputPath": null, - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 430, - "y": 193.5 - } - }, - { - "id": "portfolioExposureTable", - "name": "portfolioExposureAssessment", - "type": "decisionTableNode", - "content": { - "rules": [ - { - "_id": "rule1", - "i1-1": "> 50", - "i1-2": "assessment.marketCondition == 'severe' or assessment.marketCondition == 'high'", - "o1-1": "'critical'", - "o1-2": "0.9" - }, - { - "_id": "rule2", - "i1-1": "> 40", - "i1-2": "assessment.marketCondition == 'severe' or assessment.marketCondition == 'high'", - "o1-1": "'high'", - "o1-2": "0.7" - }, - { - "_id": "rule3", - "i1-1": "> 30", - "i1-2": "assessment.marketCondition != 'normal'", - "o1-1": "'elevated'", - "o1-2": "0.5" - }, - { - "_id": "rule4", - "i1-1": "> 20", - "i1-2": "", - "o1-1": "'moderate'", - "o1-2": "0.3" - }, - { - "_id": "rule5", - "i1-1": "", - "i1-2": "", - "o1-1": "'low'", - "o1-2": "0.1" - } - ], - "inputs": [ - { - "id": "i1-1", - "name": "High-Risk Asset Percentage", - "field": "portfolio.highRiskPercentage" - }, - { - "id": "i1-2", - "name": "Market Condition Check" - } - ], - "outputs": [ - { - "id": "o1-1", - "name": "Exposure Level", - "field": "assessment.exposureLevel" - }, - { - "id": "o1-2", - "name": "Exposure Factor", - "field": "assessment.exposureFactor" - } - ], - "hitPolicy": "first", - "inputField": null, - "outputPath": null, - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 750, - "y": 193.5 - } - }, - { - "id": "portfolioVolatilityTable", - "name": "portfolioVolatilityAssessment", - "type": "decisionTableNode", - "content": { - "rules": [ - { - "_id": "rule1", - "i1-1": "> 30", - "i1-2": "> 0.6", - "o1-1": "'high'", - "o1-2": "0.8" - }, - { - "_id": "rule2", - "i1-1": "> 25", - "i1-2": "> 0.4", - "o1-1": "'elevated'", - "o1-2": "0.6" - }, - { - "_id": "rule3", - "i1-1": "> 20", - "i1-2": "", - "o1-1": "'moderate'", - "o1-2": "0.4" - }, - { - "_id": "rule4", - "i1-1": "> 15", - "i1-2": "", - "o1-1": "'low'", - "o1-2": "0.2" - }, - { - "_id": "rule5", - "i1-1": "", - "i1-2": "", - "o1-1": "'minimal'", - "o1-2": "0.1" - } - ], - "inputs": [ - { - "id": "i1-1", - "name": "Portfolio Volatility", - "field": "portfolio.volatility" - }, - { - "id": "i1-2", - "name": "Market Risk Factor", - "field": "assessment.marketRiskFactor" - } - ], - "outputs": [ - { - "id": "o1-1", - "name": "Volatility Level", - "field": "assessment.volatilityLevel" - }, - { - "id": "o1-2", - "name": "Volatility Factor", - "field": "assessment.volatilityFactor" - } - ], - "hitPolicy": "first", - "inputField": null, - "outputPath": null, - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 1070, - "y": 193.5 - } - }, - { - "id": "riskScoreCalculation", - "name": "calculateRiskScore", - "type": "expressionNode", - "content": { - "inputField": null, - "outputPath": null, - "expressions": [ - { - "id": "expr1", - "key": "marketWeight", - "value": "0.3" - }, - { - "id": "expr2", - "key": "exposureWeight", - "value": "0.4" - }, - { - "id": "expr3", - "key": "volatilityWeight", - "value": "0.3" - }, - { - "id": "expr4", - "key": "riskScore", - "value": "assessment.marketRiskFactor * $.marketWeight + assessment.exposureFactor * $.exposureWeight + assessment.volatilityFactor * $.volatilityWeight" - }, - { - "id": "expr5", - "key": "portfolioDrift", - "value": "abs(portfolio.currentAllocation.equity - portfolio.targetAllocation.equity)" - }, - { - "id": "expr6", - "key": "riskCategory", - "value": "$.riskScore >= 0.7 ? 'critical' : $.riskScore >= 0.5 ? 'high' : $.riskScore >= 0.3 ? 'moderate' : 'low'" - } - ], - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 1390, - "y": 193.5 - } - }, - { - "id": "actionDeterminationSwitch", - "name": "determineAction", - "type": "switchNode", - "content": { - "hitPolicy": "first", - "statements": [ - { - "id": "alertAction", - "condition": "riskCategory == 'moderate' and assessment.marketCondition != 'normal'", - "isDefault": false - }, - { - "id": "rebalanceAction", - "condition": "portfolioDrift > 10 or (riskCategory == 'high' and portfolio.lastRebalance > 90)", - "isDefault": false - }, - { - "id": "mitigateAction", - "condition": "riskCategory == 'critical' or (riskCategory == 'high' and assessment.marketCondition == 'severe')", - "isDefault": false - }, - { - "id": "noAction", - "condition": "", - "isDefault": true - } - ] - }, - "position": { - "x": 1710, - "y": 193.5 - } - }, - { - "id": "alertFunction", - "name": "generateAlert", - "type": "functionNode", - "content": { - "source": "import dayjs from 'dayjs';\nexport const handler = async (input) => {\n const { customer, portfolio, assessment, riskScore, riskCategory } = input;\n const alertDate = dayjs().format('YYYY-MM-DD');\n\n return {\n action: 'alert',\n alertDetails: {\n customerId: customer.id,\n portfolioId: portfolio.id,\n date: alertDate,\n riskScore: riskScore,\n riskCategory: riskCategory,\n message: `Risk alert: Portfolio risk level is ${riskCategory} (${riskScore.toFixed(2)}). Market conditions: ${assessment.marketAssessment}`,\n recommendedAction: 'Review portfolio allocation'\n },\n outcome: { status: 'alert_generated', riskScore: riskScore, timestamp: new Date().toISOString() }\n };\n};" - }, - "position": { - "x": 2030, - "y": 46.5 - } - }, - { - "id": "rebalanceFunction", - "name": "suggestRebalancing", - "type": "functionNode", - "content": { - "source": "import dayjs from 'dayjs';\nexport const handler = async (input) => {\n const { customer, portfolio, assessment, riskScore, riskCategory, portfolioDrift } = input;\n const currentDate = dayjs().format('YYYY-MM-DD');\n const suggestedEquity = portfolio.targetAllocation.equity;\n const suggestedBonds = portfolio.targetAllocation.bonds;\n const suggestedCash = portfolio.targetAllocation.cash;\n const driftPercentage = portfolioDrift.toFixed(1);\n\n return {\n action: 'rebalance',\n rebalanceDetails: {\n customerId: customer.id,\n portfolioId: portfolio.id,\n date: currentDate,\n riskScore: riskScore,\n riskCategory: riskCategory,\n currentAllocation: portfolio.currentAllocation,\n targetAllocation: portfolio.targetAllocation,\n driftPercentage: driftPercentage,\n suggestedChanges: {\n equity: suggestedEquity - portfolio.currentAllocation.equity,\n bonds: suggestedBonds - portfolio.currentAllocation.bonds,\n cash: suggestedCash - portfolio.currentAllocation.cash\n },\n message: `Rebalancing recommended: Portfolio has drifted ${driftPercentage}% from target allocation.`\n },\n outcome: { status: 'rebalance_suggested', riskScore: riskScore, timestamp: new Date().toISOString() }\n };\n};" - }, - "position": { - "x": 2030, - "y": 144.5 - } - }, - { - "id": "mitigationFunction", - "name": "implementRiskMitigation", - "type": "functionNode", - "content": { - "source": "import dayjs from 'dayjs';\nexport const handler = async (input) => {\n const { customer, portfolio, assessment, riskScore, riskCategory } = input;\n const mitigationDate = dayjs().format('YYYY-MM-DD');\n const suggestedEquity = Math.max(portfolio.targetAllocation.equity - 15, 0);\n const suggestedBonds = Math.min(portfolio.targetAllocation.bonds + 10, 100 - suggestedEquity - 5);\n const suggestedCash = 100 - suggestedEquity - suggestedBonds;\n\n return {\n action: 'mitigate',\n mitigationDetails: {\n customerId: customer.id,\n portfolioId: portfolio.id,\n date: mitigationDate,\n riskScore: riskScore,\n riskCategory: riskCategory,\n currentAllocation: portfolio.currentAllocation,\n suggestedAllocation: { equity: suggestedEquity, bonds: suggestedBonds, cash: suggestedCash },\n message: `Risk mitigation required: Market conditions (${assessment.marketCondition}) and portfolio risk (${riskCategory}) indicate immediate action needed.`,\n automaticChanges: assessment.marketCondition === 'severe' && riskCategory === 'critical' && customer.preferences.allowAutomaticAdjustments\n },\n outcome: { status: 'mitigation_implemented', riskScore: riskScore, timestamp: new Date().toISOString() }\n };\n};" - }, - "position": { - "x": 2030, - "y": 242.5 - } - }, - { - "id": "noActionRequired", - "name": "noActionNeeded", - "type": "expressionNode", - "content": { - "inputField": null, - "outputPath": null, - "expressions": [ - { - "id": "expr1", - "key": "outcome", - "value": "{ status: 'no_action_required', riskScore: riskScore, timestamp: string(date('now')) }" - } - ], - "passThrough": true, - "executionMode": "single" - }, - "position": { - "x": 2030, - "y": 340.5 - } - } - ], - "edges": [ - { - "id": "edge1", - "type": "edge", - "sourceId": "inputNode", - "targetId": "marketConditionsTable" - }, - { - "id": "edge2", - "type": "edge", - "sourceId": "marketConditionsTable", - "targetId": "portfolioExposureTable" - }, - { - "id": "edge3", - "type": "edge", - "sourceId": "portfolioExposureTable", - "targetId": "portfolioVolatilityTable" - }, - { - "id": "edge4", - "type": "edge", - "sourceId": "portfolioVolatilityTable", - "targetId": "riskScoreCalculation" - }, - { - "id": "edge5", - "type": "edge", - "sourceId": "riskScoreCalculation", - "targetId": "actionDeterminationSwitch" - }, - { - "id": "edge6", - "type": "edge", - "sourceId": "actionDeterminationSwitch", - "targetId": "alertFunction", - "sourceHandle": "alertAction" - }, - { - "id": "edge7", - "type": "edge", - "sourceId": "actionDeterminationSwitch", - "targetId": "rebalanceFunction", - "sourceHandle": "rebalanceAction" - }, - { - "id": "edge8", - "type": "edge", - "sourceId": "actionDeterminationSwitch", - "targetId": "mitigationFunction", - "sourceHandle": "mitigateAction" - }, - { - "id": "edge9", - "type": "edge", - "sourceId": "actionDeterminationSwitch", - "targetId": "noActionRequired", - "sourceHandle": "noAction" - } - ] -} \ No newline at end of file diff --git a/test-data/graphs/preventive-care-recommendation.json b/test-data/graphs/preventive-care-recommendation.json deleted file mode 100644 index 079bed42..00000000 --- a/test-data/graphs/preventive-care-recommendation.json +++ /dev/null @@ -1,370 +0,0 @@ -{ - "tests": [ - { - "input": { - "firstName": "Jane", - "lastName": "Smith", - "age": 42, - "sex": "female", - "familyHistory": [ - "breast cancer", - "diabetes" - ], - "riskFactors": [ - "smoking" - ], - "lastCheckup": "2023-10-15" - }, - "output": { - "patientName": "Jane Smith", - "recommendationDate": "2025-08-19 16:55:02", - "summarizedRecommendations": [ - { - "genderBasedRecommendations": { - "primary": "Mammogram every 1-2 years (discuss with doctor)", - "secondary": "Cervical cancer screening every 3 years" - } - }, - { - "ageBasedRecommendations": { - "primary": "Blood pressure screening", - "quaternary": "Eye exam every 2-4 years", - "secondary": "Cholesterol screening every 5 years", - "tertiary": "Diabetes screening every 3 years" - } - }, - { - "riskBasedRecommendations": "Earlier and more frequent diabetes screening" - }, - { - "riskBasedRecommendations": "Earlier and more frequent mammograms" - }, - { - "riskBasedRecommendations": "Lung cancer screening" - } - ], - "totalRecommendations": 5 - } - } - ], - "nodes": [ - { - "type": "inputNode", - "content": { - "schema": "" - }, - "id": "input", - "name": "patientData", - "position": { - "x": 110, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "collect", - "rules": [ - { - "_id": "age1", - "i1": "< 18", - "o1": "\"Annual physical examination\"", - "o2": "\"Immunizations as per schedule\"", - "o3": "\"Vision screening\"", - "o4": "\"Dental checkup every 6 months\"" - }, - { - "_id": "age2", - "i1": ">= 18 and < 40", - "o1": "\"Blood pressure screening\"", - "o2": "\"Cholesterol screening every 5 years\"", - "o3": "\"Depression screening\"", - "o4": "\"Skin cancer screening\"" - }, - { - "_id": "age3", - "i1": ">= 40 and < 50", - "o1": "\"Blood pressure screening\"", - "o2": "\"Cholesterol screening every 5 years\"", - "o3": "\"Diabetes screening every 3 years\"", - "o4": "\"Eye exam every 2-4 years\"" - }, - { - "_id": "age4", - "i1": ">= 50 and < 65", - "o1": "\"Blood pressure screening\"", - "o2": "\"Cholesterol screening annually\"", - "o3": "\"Diabetes screening every 3 years\"", - "o4": "\"Colorectal cancer screening\"" - }, - { - "_id": "age5", - "i1": ">= 65", - "o1": "\"Blood pressure screening\"", - "o2": "\"Cholesterol screening annually\"", - "o3": "\"Diabetes screening annually\"", - "o4": "\"Fall risk assessment\"" - } - ], - "inputs": [ - { - "id": "i1", - "name": "Age", - "field": "age" - } - ], - "outputs": [ - { - "id": "o1", - "name": "Recommendation1", - "field": "recommendations.ageBasedRecommendations.primary" - }, - { - "id": "o2", - "name": "Recommendation2", - "field": "recommendations.ageBasedRecommendations.secondary" - }, - { - "id": "o3", - "name": "Recommendation3", - "field": "recommendations.ageBasedRecommendations.tertiary" - }, - { - "id": "o4", - "name": "Recommendation4", - "field": "recommendations.ageBasedRecommendations.quaternary" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": "recommendations.age", - "executionMode": "single", - "passThorough": false - }, - "id": "ageSpecificScreenings", - "name": "ageBasedRecommendations", - "position": { - "x": 430, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "collect", - "rules": [ - { - "_id": "gender1", - "i1": "'female'", - "i2": "[21..30)", - "o1": "\"Cervical cancer screening every 3 years\"", - "o2": "\"Chlamydia screening annually (if sexually active)\"" - }, - { - "_id": "gender2", - "i1": "'female'", - "i2": "[30..40)", - "o1": "\"Cervical cancer screening every 3 years\"", - "o2": "\"HPV testing every 5 years\"" - }, - { - "_id": "gender3", - "i1": "'female'", - "i2": "[40..50)", - "o1": "\"Mammogram every 1-2 years (discuss with doctor)\"", - "o2": "\"Cervical cancer screening every 3 years\"" - }, - { - "_id": "gender4", - "i1": "'female'", - "i2": "[50..75)", - "o1": "\"Mammogram every 2 years\"", - "o2": "\"Bone density screening (65+ or at risk)\"" - }, - { - "_id": "gender5", - "i1": "'male'", - "i2": "[40..55)", - "o1": "\"Prostate health discussion with doctor\"", - "o2": "\"Testicular exam\"" - }, - { - "_id": "gender6", - "i1": "'male'", - "i2": "[55..70)", - "o1": "\"Prostate cancer screening (discuss with doctor)\"", - "o2": "\"Abdominal aortic aneurysm screening (if ever smoked)\"" - } - ], - "inputs": [ - { - "id": "i1", - "name": "Sex", - "field": "sex" - }, - { - "id": "i2", - "name": "Age", - "field": "age" - } - ], - "outputs": [ - { - "id": "o1", - "name": "GenderRecommendation1", - "field": "recommendations.genderBasedRecommendations.primary" - }, - { - "id": "o2", - "name": "GenderRecommendation2", - "field": "recommendations.genderBasedRecommendations.secondary" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": "recommendations.sex", - "executionMode": "single" - }, - "id": "genderSpecificScreenings", - "name": "sexBasedRecommendations", - "position": { - "x": 750, - "y": 114 - } - }, - { - "type": "decisionTableNode", - "content": { - "hitPolicy": "collect", - "rules": [ - { - "_id": "risk1", - "i1": "contains(familyHistory, \"diabetes\")", - "o1": "\"Earlier and more frequent diabetes screening\"" - }, - { - "_id": "risk2", - "i1": "contains(familyHistory, \"heart disease\")", - "o1": "\"Earlier and more frequent cholesterol and blood pressure monitoring\"" - }, - { - "_id": "risk3", - "i1": "contains(familyHistory, \"colorectal cancer\")", - "o1": "\"Earlier colorectal cancer screening (before age 45)\"" - }, - { - "_id": "risk4", - "i1": "contains(familyHistory, \"breast cancer\")", - "o1": "\"Earlier and more frequent mammograms\"" - }, - { - "_id": "risk5", - "i1": "contains(riskFactors, \"smoking\")", - "o1": "\"Lung cancer screening\"" - }, - { - "_id": "risk6", - "i1": "contains(riskFactors, \"obesity\")", - "o1": "\"More frequent diabetes and heart disease screenings\"" - }, - { - "_id": "risk7", - "i1": "contains(riskFactors, \"alcohol abuse\")", - "o1": "\"Liver function tests\"" - } - ], - "inputs": [ - { - "id": "i1", - "name": "Risk Assessment" - } - ], - "outputs": [ - { - "id": "o1", - "name": "RiskRecommendation", - "field": "recommendations.riskBasedRecommendations" - } - ], - "passThrough": true, - "inputField": null, - "outputPath": "recommendations.risk", - "executionMode": "single" - }, - "id": "riskFactorScreenings", - "name": "riskBasedRecommendations", - "position": { - "x": 1070, - "y": 114 - } - }, - { - "type": "expressionNode", - "content": { - "expressions": [ - { - "id": "expr1", - "key": "summarizedRecommendations", - "value": "flatMap(flatten(values(recommendations)), #.recommendations)" - }, - { - "id": "expr3", - "key": "patientName", - "value": "`${firstName} ${lastName}`" - }, - { - "id": "expr4", - "key": "recommendationDate", - "value": "dateString(date(\"now\"))" - }, - { - "id": "expr5", - "key": "totalRecommendations", - "value": "len($.summarizedRecommendations)" - }, - { - "id": "27928cee-be10-4e77-8089-f4ca14541539", - "key": "testResults", - "value": "null" - } - ], - "passThrough": false, - "inputField": null, - "outputPath": null, - "executionMode": "single" - }, - "id": "generateRecommendations", - "name": "finalRecommendations", - "position": { - "x": 1390, - "y": 114 - } - } - ], - "edges": [ - { - "id": "edge1", - "sourceId": "input", - "targetId": "ageSpecificScreenings", - "type": "edge" - }, - { - "id": "edge2", - "sourceId": "ageSpecificScreenings", - "targetId": "genderSpecificScreenings", - "type": "edge" - }, - { - "id": "edge3", - "sourceId": "genderSpecificScreenings", - "targetId": "riskFactorScreenings", - "type": "edge" - }, - { - "id": "edge4", - "sourceId": "riskFactorScreenings", - "targetId": "generateRecommendations", - "type": "edge" - } - ] -} \ No newline at end of file From 1f9e0ba602d5bcc18fb19710b10f3b7b37735d11 Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 20 Aug 2025 12:42:50 +0200 Subject: [PATCH 08/14] fix --- core/expression/Cargo.toml | 1 + core/expression/src/vm/date/mod.rs | 6 +++--- core/expression/src/vm/mod.rs | 3 +++ test-data/graphs/customer-lifetime-value.json | 8 ++++---- test-data/graphs/environment-compliance-assessment.json | 2 +- test-data/graphs/immigration-eligibility-evaluator.json | 2 +- .../graphs/marketplace-listing-verification-system.json | 2 +- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/core/expression/Cargo.toml b/core/expression/Cargo.toml index cd0c4fdc..75d55a05 100644 --- a/core/expression/Cargo.toml +++ b/core/expression/Cargo.toml @@ -40,6 +40,7 @@ default = ["regex-deprecated", "stack-protection"] regex-lite = ["dep:regex-lite"] regex-deprecated = ["dep:regex"] stack-protection = ["dep:recursive"] +time-override = [] [[bench]] harness = false diff --git a/core/expression/src/vm/date/mod.rs b/core/expression/src/vm/date/mod.rs index 858fad24..c150e304 100644 --- a/core/expression/src/vm/date/mod.rs +++ b/core/expression/src/vm/date/mod.rs @@ -180,7 +180,7 @@ mod helper { use crate::Variable; use chrono::{ DateTime, Datelike, Days, LocalResult, Month, Months, NaiveDate, NaiveDateTime, Offset, - TimeDelta, TimeZone, Timelike, Utc, + TimeDelta, TimeZone, Timelike, }; use chrono_tz::Tz; use rust_decimal::prelude::ToPrimitive; @@ -482,12 +482,12 @@ impl dyn DynamicVariable { } } -#[cfg(test)] +#[cfg(feature = "time-override")] pub static UTC_OVERRIDE: LazyLock>>> = LazyLock::new(|| RwLock::new(None)); pub(crate) fn utc_now() -> DateTime { - #[cfg(test)] + #[cfg(feature = "time-override")] { if let Ok(override_time) = UTC_OVERRIDE.read() { if let Some(time) = *override_time { diff --git a/core/expression/src/vm/mod.rs b/core/expression/src/vm/mod.rs index ac3fa557..19c6c4b9 100644 --- a/core/expression/src/vm/mod.rs +++ b/core/expression/src/vm/mod.rs @@ -11,3 +11,6 @@ mod interval; mod vm; pub(crate) use date::VmDate; + +#[cfg(feature = "time-override")] +pub use date::UTC_OVERRIDE; diff --git a/test-data/graphs/customer-lifetime-value.json b/test-data/graphs/customer-lifetime-value.json index 2e0df62d..f0f70df7 100644 --- a/test-data/graphs/customer-lifetime-value.json +++ b/test-data/graphs/customer-lifetime-value.json @@ -23,10 +23,10 @@ } }, "output": { - "acquisitionCostRatio": 0.009543603664743808, - "adjustedLTV": 15567.333333333334, + "acquisitionCostRatio": 0.0095436036647438072616219885, + "adjustedLTV": 15567.333333333333333333333334, "averageOrderValue": 168.4, - "basicLTV": 15717.333333333334, + "basicLTV": 15717.333333333333333333333334, "customer": { "acquisitionChannel": "paid_search", "acquisitionCost": 150, @@ -40,7 +40,7 @@ }, "customerLifetimeMonths": 80, "grossMargin": 0.35, - "purchaseFrequency": 3.3333333333333335, + "purchaseFrequency": 3.3333333333333333333333333336, "purchaseHistory": { "averageGrossMarginPercent": 35, "customerDurationMonths": 18, diff --git a/test-data/graphs/environment-compliance-assessment.json b/test-data/graphs/environment-compliance-assessment.json index 69bd03d7..863da5f9 100644 --- a/test-data/graphs/environment-compliance-assessment.json +++ b/test-data/graphs/environment-compliance-assessment.json @@ -64,7 +64,7 @@ "country": "United States", "region": "midwest" }, - "percentOverThreshold": 23.333333333333332, + "percentOverThreshold": 23.33333333333333333333333333, "production": { "units": "million_units", "volume": 100 diff --git a/test-data/graphs/immigration-eligibility-evaluator.json b/test-data/graphs/immigration-eligibility-evaluator.json index 335c1740..9312e60c 100644 --- a/test-data/graphs/immigration-eligibility-evaluator.json +++ b/test-data/graphs/immigration-eligibility-evaluator.json @@ -57,7 +57,7 @@ "finalStatus": "approved", "languageReason": "Advanced language proficiency", "languageScore": 75, - "overallScore": 85.83333333333333 + "overallScore": 85.83333333333333333333333333 }, "background": { "criminalHistory": false, diff --git a/test-data/graphs/marketplace-listing-verification-system.json b/test-data/graphs/marketplace-listing-verification-system.json index 005511c7..b97cfb62 100644 --- a/test-data/graphs/marketplace-listing-verification-system.json +++ b/test-data/graphs/marketplace-listing-verification-system.json @@ -55,7 +55,7 @@ "price": 950, "title": "Designer Handbag - Limited Edition" }, - "priceDeviationScore": 36.666666666666664, + "priceDeviationScore": 36.66666666666666666666666667, "riskAssessment": { "level": "high", "reason": "Suspicious pricing for high-value brand with history of violations" From 1b04e93a8308856c5a070575d8035ac33677ad27 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Wed, 20 Aug 2025 15:40:14 +0200 Subject: [PATCH 09/14] Node.js test fix --- bindings/nodejs/test/decision.spec.ts | 36 +++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/bindings/nodejs/test/decision.spec.ts b/bindings/nodejs/test/decision.spec.ts index 4b1cb237..7b746449 100644 --- a/bindings/nodejs/test/decision.spec.ts +++ b/bindings/nodejs/test/decision.spec.ts @@ -17,6 +17,37 @@ const loader = async (key: string) => fs.readFile(path.join(testDataRoot, key)) jest.useRealTimers(); +interface PropertyMatcher { + [key: string]: any; +} + +const defaultMatchers: PropertyMatcher = { + timestamp: expect.any(Number), + estimatedArrival: expect.any(Number), + approvalDate: expect.any(Number), +}; + +function addJestMatchers(obj: any, matchers: PropertyMatcher = defaultMatchers): any { + if (obj === null || typeof obj !== 'object') { + return obj; + } + + if (Array.isArray(obj)) { + return obj.map((item: any) => addJestMatchers(item, matchers)); + } + + const result: Record = {}; + for (const [key, value] of Object.entries(obj)) { + if (matchers[key]) { + result[key] = matchers[key]; + } else { + result[key] = addJestMatchers(value, matchers); + } + } + + return result; +} + describe('ZenEngine', () => { it('Evaluates decisions using loader', async () => { const engine = new ZenEngine({ @@ -128,9 +159,10 @@ describe('ZenEngine', () => { assert.ok(engineResponse.success, 'Engine response must be ok'); assert.ok(decisionResponse.success, 'Decision response must be ok'); + const expectedObject = addJestMatchers(testCase.output); - expect(engineResponse.data.result).toMatchObject(testCase.output); - expect(decisionResponse.data.result).toMatchObject(testCase.output); + expect(engineResponse.data.result).toMatchObject(expectedObject); + expect(decisionResponse.data.result).toMatchObject(expectedObject); } } From 654375c90f8d6a216039b6abc63a7895eadab6c9 Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 20 Aug 2025 16:33:27 +0200 Subject: [PATCH 10/14] fix merge --- core/engine/src/handler/expression/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/engine/src/handler/expression/mod.rs b/core/engine/src/handler/expression/mod.rs index 9a562088..d6caf068 100644 --- a/core/engine/src/handler/expression/mod.rs +++ b/core/engine/src/handler/expression/mod.rs @@ -82,7 +82,7 @@ impl<'a> ExpressionHandlerInner<'a> { tmap.insert( Rc::from(expression.key.as_str()), ExpressionTrace { - result: value.to_value(), + result: value.clone(), }, ); } From 1326a2072a29124a9bee3cbfc930d016cd9a42fc Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 21 Aug 2025 12:44:33 +0200 Subject: [PATCH 11/14] fix utc override --- bindings/nodejs/package.json | 2 +- bindings/nodejs/src/types.rs | 2 + bindings/nodejs/test/decision.spec.ts | 114 +++++++++----------------- bindings/python/pyproject.toml | 1 + bindings/python/test_async.py | 2 + bindings/python/test_sync.py | 6 +- core/engine/Cargo.toml | 1 - core/engine/tests/engine.rs | 3 +- core/expression/Cargo.toml | 1 - core/expression/src/parser/ast.rs | 2 +- core/expression/src/vm/date/mod.rs | 25 +++--- core/expression/src/vm/helpers.rs | 4 +- core/expression/src/vm/mod.rs | 3 - 13 files changed, 65 insertions(+), 101 deletions(-) diff --git a/bindings/nodejs/package.json b/bindings/nodejs/package.json index 32ecffc3..3ae88acb 100644 --- a/bindings/nodejs/package.json +++ b/bindings/nodejs/package.json @@ -78,7 +78,7 @@ "build": "napi build --dts temp.d.ts --platform --release", "build:debug": "napi build --platform --js index.js --dts index.d.ts", "watch": "cargo watch --ignore '{index.js,index.d.ts}' -- npm run build:debug", - "test": "jest", + "test": "__ZEN_MOCK_UTC_TIME=2025-08-19T16:55:02.078Z jest", "artifacts": "napi artifacts -d ../../artifacts", "prepublishOnly": "napi prepublish", "version": "napi version" diff --git a/bindings/nodejs/src/types.rs b/bindings/nodejs/src/types.rs index d6eb9f39..14a423ce 100644 --- a/bindings/nodejs/src/types.rs +++ b/bindings/nodejs/src/types.rs @@ -9,6 +9,7 @@ use zen_engine::handler::custom_node_adapter::CustomDecisionNode; use zen_engine::{DecisionGraphResponse, DecisionGraphTrace}; use zen_expression::Variable; +#[allow(dead_code)] #[napi(object)] pub struct ZenEngineTrace { pub id: String, @@ -34,6 +35,7 @@ impl From for ZenEngineTrace { } } +#[allow(dead_code)] #[napi(object)] pub struct ZenEngineResponse { pub performance: String, diff --git a/bindings/nodejs/test/decision.spec.ts b/bindings/nodejs/test/decision.spec.ts index 7b746449..1dccdec8 100644 --- a/bindings/nodejs/test/decision.spec.ts +++ b/bindings/nodejs/test/decision.spec.ts @@ -4,59 +4,28 @@ import { evaluateUnaryExpression, renderTemplate, evaluateExpressionSync, - evaluateUnaryExpressionSync, renderTemplateSync, ZenDecisionContent -} from "../index"; + evaluateUnaryExpressionSync, renderTemplateSync, ZenDecisionContent, +} from '../index'; import fs from 'fs/promises'; import path from 'path'; -import {describe, expect, it, jest} from "@jest/globals"; -import assert from "assert"; +import { describe, expect, it, jest } from '@jest/globals'; +import assert from 'assert'; const testDataRoot = path.join(__dirname, '../../../', 'test-data'); -const loader = async (key: string) => fs.readFile(path.join(testDataRoot, key)) +const loader = async (key: string) => fs.readFile(path.join(testDataRoot, key)); jest.useRealTimers(); -interface PropertyMatcher { - [key: string]: any; -} - -const defaultMatchers: PropertyMatcher = { - timestamp: expect.any(Number), - estimatedArrival: expect.any(Number), - approvalDate: expect.any(Number), -}; - -function addJestMatchers(obj: any, matchers: PropertyMatcher = defaultMatchers): any { - if (obj === null || typeof obj !== 'object') { - return obj; - } - - if (Array.isArray(obj)) { - return obj.map((item: any) => addJestMatchers(item, matchers)); - } - - const result: Record = {}; - for (const [key, value] of Object.entries(obj)) { - if (matchers[key]) { - result[key] = matchers[key]; - } else { - result[key] = addJestMatchers(value, matchers); - } - } - - return result; -} - describe('ZenEngine', () => { it('Evaluates decisions using loader', async () => { const engine = new ZenEngine({ - loader + loader, }); - const r1 = await engine.evaluate('function.json', {input: 5}); - const r2 = await engine.evaluate('table.json', {input: 2}); - const r3 = await engine.evaluate('table.json', {input: 12}); + const r1 = await engine.evaluate('function.json', { input: 5 }); + const r2 = await engine.evaluate('table.json', { input: 2 }); + const r3 = await engine.evaluate('table.json', { input: 12 }); expect(r1.result.output).toEqual(10); expect(r2.result.output).toEqual(0); @@ -73,9 +42,9 @@ describe('ZenEngine', () => { const functionDecision = await engine.getDecision('function.json'); const tableDecision = await engine.getDecision('table.json'); - const r1 = await functionDecision.evaluate({input: 10}); - const r2 = await tableDecision.evaluate({input: 5}); - const r3 = await tableDecision.evaluate({input: 12}); + const r1 = await functionDecision.evaluate({ input: 10 }); + const r2 = await tableDecision.evaluate({ input: 5 }); + const r3 = await tableDecision.evaluate({ input: 12 }); expect(r1.result.output).toEqual(20); expect(r2.result.output).toEqual(0); @@ -89,9 +58,9 @@ describe('ZenEngine', () => { const functionContent = await fs.readFile(path.join(testDataRoot, 'function.json')); const functionDecision = engine.createDecision(functionContent); - const r = await functionDecision.evaluate({input: 15}); + const r = await functionDecision.evaluate({ input: 15 }); expect(r.result.output).toEqual(30); - }, 10000) + }, 10000); it('Evaluate custom nodes with a handler', async () => { const engine = new ZenEngine({ @@ -101,20 +70,20 @@ describe('ZenEngine', () => { const prop1Raw = request.getFieldRaw('prop1'); expect(prop1).toEqual(15); - expect(prop1Raw).toEqual('{{ a + 10 }}') + expect(prop1Raw).toEqual('{{ a + 10 }}'); expect(request.node).toMatchObject({ id: '138b3b11-ff46-450f-9704-3f3c712067b2', name: 'customNode1', kind: 'sum', config: { - prop1: '{{ a + 10 }}' - } + prop1: '{{ a + 10 }}', + }, }); - return {output: {data: prop1 + 10}} - } + return { output: { data: prop1 + 10 } }; + }, }); - const r = await engine.evaluate('custom.json', {a: 5}); + const r = await engine.evaluate('custom.json', { a: 5 }); expect(r.result.data).toEqual(25); engine.dispose(); @@ -140,7 +109,7 @@ describe('ZenEngine', () => { const graphsRoot = path.join(testDataRoot, 'graphs'); const loader = async (key: string) => fs.readFile(path.join(graphsRoot, key)); - const engine = new ZenEngine({loader}); + const engine = new ZenEngine({ loader }); const entries = await fs.readdir(graphsRoot); for (const entry of entries) { @@ -159,28 +128,27 @@ describe('ZenEngine', () => { assert.ok(engineResponse.success, 'Engine response must be ok'); assert.ok(decisionResponse.success, 'Decision response must be ok'); - const expectedObject = addJestMatchers(testCase.output); - expect(engineResponse.data.result).toMatchObject(expectedObject); - expect(decisionResponse.data.result).toMatchObject(expectedObject); + expect(engineResponse.data.result).toMatchObject(testCase.output); + expect(decisionResponse.data.result).toMatchObject(testCase.output); } } engine.dispose(); - }) -}) + }); +}); describe('Expressions', () => { it('Evaluates standard expressions', async () => { const expressions = [ - {expression: '1 + 1', result: 2}, - {expression: 'a > b', context: {a: 5, b: 3}, result: true}, - {expression: 'sum(a)', context: {a: [1, 2, 3, 4]}, result: 10}, - {expression: 'contains("some", "none")', result: false}, - {expression: 'matches("test@email.com", "\\w+@\\w+\\.com")', result: true}, + { expression: '1 + 1', result: 2 }, + { expression: 'a > b', context: { a: 5, b: 3 }, result: true }, + { expression: 'sum(a)', context: { a: [1, 2, 3, 4] }, result: 10 }, + { expression: 'contains("some", "none")', result: false }, + { expression: 'matches("test@email.com", "\\w+@\\w+\\.com")', result: true }, ]; - for (const {expression, result, context} of expressions) { + for (const { expression, result, context } of expressions) { expect(await evaluateExpression(expression, context)).toEqual(result); expect(evaluateExpressionSync(expression, context)).toEqual(result); } @@ -188,13 +156,13 @@ describe('Expressions', () => { it('Evaluates unary expressions', async () => { const expressions = [ - {expression: '>= 5', context: {$: 5}, result: true}, - {expression: '< 5', context: {$: 5}, result: false}, - {expression: '"FR", "ES"', context: {$: 'GB'}, result: false}, - {expression: 'contains($, "some")', context: {$: 'some-string'}, result: true}, + { expression: '>= 5', context: { $: 5 }, result: true }, + { expression: '< 5', context: { $: 5 }, result: false }, + { expression: '"FR", "ES"', context: { $: 'GB' }, result: false }, + { expression: 'contains($, "some")', context: { $: 'some-string' }, result: true }, ]; - for (const {expression, result, context} of expressions) { + for (const { expression, result, context } of expressions) { expect(await evaluateUnaryExpression(expression, context)).toEqual(result); expect(evaluateUnaryExpressionSync(expression, context)).toEqual(result); } @@ -202,13 +170,13 @@ describe('Expressions', () => { it('Renders templates', async () => { const templateCases = [ - {template: '{{ a + 10 }}', context: {a: 10}, result: 20}, - {template: '{{ a + 10 }}', context: {a: 15}, result: 25}, - {template: '{{ a + 10 }}', context: {a: 20}, result: 30}, - {template: '{{ a + 10 }}', context: {a: 25}, result: 35}, + { template: '{{ a + 10 }}', context: { a: 10 }, result: 20 }, + { template: '{{ a + 10 }}', context: { a: 15 }, result: 25 }, + { template: '{{ a + 10 }}', context: { a: 20 }, result: 30 }, + { template: '{{ a + 10 }}', context: { a: 25 }, result: 35 }, ]; - for (const {template, context, result} of templateCases) { + for (const { template, context, result } of templateCases) { expect(await renderTemplate(template, context)).toEqual(result); expect(renderTemplateSync(template, context)).toEqual(result); } diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index ef9b8542..a3885756 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -4,6 +4,7 @@ build-backend = "maturin" [project] name = "zen-engine" +dynamic = ["version"] requires-python = ">=3.7" classifiers = [ "Programming Language :: Rust", diff --git a/bindings/python/test_async.py b/bindings/python/test_async.py index eeddd29a..0efad8e7 100644 --- a/bindings/python/test_async.py +++ b/bindings/python/test_async.py @@ -4,9 +4,11 @@ import os.path import time import unittest +import os import zen +os.environ['__ZEN_MOCK_UTC_TIME'] = '2025-08-19T16:55:02.078Z' async def loader(key): with open("../../test-data/" + key, "r") as f: diff --git a/bindings/python/test_sync.py b/bindings/python/test_sync.py index b6f444c0..8472d6df 100644 --- a/bindings/python/test_sync.py +++ b/bindings/python/test_sync.py @@ -2,9 +2,11 @@ import os.path import unittest import glob +import os import zen +os.environ['__ZEN_MOCK_UTC_TIME'] = '2025-08-19T16:55:02.078Z' def loader(key): with open("../../test-data/" + key, "r") as f: @@ -111,8 +113,8 @@ def test_evaluate_graphs(self): decision = engine.get_decision(key) decision_response = decision.evaluate(test_case["input"]) - self.assertEqual(engine_response["result"], test_case["output"]) - self.assertEqual(decision_response["result"], test_case["output"]) + self.assertEqual(engine_response["result"], test_case["output"], key) + self.assertEqual(decision_response["result"], test_case["output"], key) if __name__ == '__main__': unittest.main() diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 0a432310..7c9cf892 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -34,7 +34,6 @@ chrono = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } criterion = { workspace = true, features = ["async_tokio"] } insta = { version = "1.43", features = ["yaml", "redactions"] } -zen-expression = { path = "../expression", version = "0.49.1", features = ["time-override"] } [[bench]] harness = false diff --git a/core/engine/tests/engine.rs b/core/engine/tests/engine.rs index bb40a2dc..31592e7e 100644 --- a/core/engine/tests/engine.rs +++ b/core/engine/tests/engine.rs @@ -12,7 +12,6 @@ use zen_engine::loader::{LoaderError, MemoryLoader}; use zen_engine::model::{DecisionContent, DecisionNode, DecisionNodeKind, FunctionNodeContent}; use zen_engine::{DecisionEngine, EvaluationError, EvaluationOptions}; use zen_engine::{NodeError, Variable}; -use zen_expression::vm::UTC_OVERRIDE; mod support; @@ -271,7 +270,7 @@ async fn engine_graph_tests() { } fn mock_datetime() { - *UTC_OVERRIDE.write().unwrap() = Some("2025-08-19T16:55:02.078Z".parse().unwrap()); + std::env::set_var("__ZEN_MOCK_UTC_TIME", "2025-08-19T16:55:02.078Z"); } #[tokio::test] diff --git a/core/expression/Cargo.toml b/core/expression/Cargo.toml index eb01d6bb..edbbbcde 100644 --- a/core/expression/Cargo.toml +++ b/core/expression/Cargo.toml @@ -43,7 +43,6 @@ default = ["regex-deprecated", "stack-protection"] regex-lite = ["dep:regex-lite"] regex-deprecated = ["dep:regex"] stack-protection = ["dep:recursive"] -time-override = [] [[bench]] harness = false diff --git a/core/expression/src/parser/ast.rs b/core/expression/src/parser/ast.rs index 42681a8e..a61f6401 100644 --- a/core/expression/src/parser/ast.rs +++ b/core/expression/src/parser/ast.rs @@ -154,7 +154,7 @@ impl<'a> Node<'a> { }; } - pub fn first_error(&self) -> Option { + pub fn first_error(&'a self) -> Option> { let error_cell = Cell::new(None); self.walk(|n| { if let Node::Error { error, .. } = n { diff --git a/core/expression/src/vm/date/mod.rs b/core/expression/src/vm/date/mod.rs index 41deb5cd..225c2709 100644 --- a/core/expression/src/vm/date/mod.rs +++ b/core/expression/src/vm/date/mod.rs @@ -7,7 +7,7 @@ use chrono_tz::Tz; use serde_json::Value; use std::any::Any; use std::fmt::{Display, Formatter}; -use std::sync::{LazyLock, RwLock}; +use std::sync::OnceLock; // Duration is a modified copy of `humantime` mod duration; @@ -486,19 +486,16 @@ impl DynamicVariableExt for dyn DynamicVariable { } } -#[cfg(feature = "time-override")] -pub static UTC_OVERRIDE: LazyLock>>> = - LazyLock::new(|| RwLock::new(None)); - pub(crate) fn utc_now() -> DateTime { - #[cfg(feature = "time-override")] - { - if let Ok(override_time) = UTC_OVERRIDE.read() { - if let Some(time) = *override_time { - return time; - } - } - } + static CURRENT_DATE_VALUE: OnceLock>> = OnceLock::new(); - Utc::now() + CURRENT_DATE_VALUE + .get_or_init(|| match std::env::var("__ZEN_MOCK_UTC_TIME") { + Ok(v) => { + let now = v.parse::>().unwrap(); + Some(now) + } + Err(_) => None, + }) + .unwrap_or_else(|| Utc::now()) } diff --git a/core/expression/src/vm/helpers.rs b/core/expression/src/vm/helpers.rs index a58778ae..2ce36a3d 100644 --- a/core/expression/src/vm/helpers.rs +++ b/core/expression/src/vm/helpers.rs @@ -1,8 +1,6 @@ use crate::vm::date::utc_now; use crate::vm::error::{VMError, VMResult}; -use chrono::{ - DateTime, Datelike, Days, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc, Weekday, -}; +use chrono::{DateTime, Datelike, Days, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Weekday}; use once_cell::sync::Lazy; #[allow(clippy::unwrap_used)] diff --git a/core/expression/src/vm/mod.rs b/core/expression/src/vm/mod.rs index 19c6c4b9..ac3fa557 100644 --- a/core/expression/src/vm/mod.rs +++ b/core/expression/src/vm/mod.rs @@ -11,6 +11,3 @@ mod interval; mod vm; pub(crate) use date::VmDate; - -#[cfg(feature = "time-override")] -pub use date::UTC_OVERRIDE; From a8e1caa488b823b185061b100e39294f8b5e04ee Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 21 Aug 2025 20:52:21 +0200 Subject: [PATCH 12/14] fix cross-env --- bindings/nodejs/package.json | 3 ++- bindings/nodejs/yarn.lock | 13 +++++++++++++ bindings/python/pyproject.toml | 1 - 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/bindings/nodejs/package.json b/bindings/nodejs/package.json index 3ae88acb..d96112f7 100644 --- a/bindings/nodejs/package.json +++ b/bindings/nodejs/package.json @@ -55,6 +55,7 @@ "@types/express": "^5.0.1", "@types/node": "^22.14.1", "babel-jest": "^29.7.0", + "cross-env": "^10.0.0", "express": "^5.1.0", "jest": "^29.7.0", "lerna": "6", @@ -78,7 +79,7 @@ "build": "napi build --dts temp.d.ts --platform --release", "build:debug": "napi build --platform --js index.js --dts index.d.ts", "watch": "cargo watch --ignore '{index.js,index.d.ts}' -- npm run build:debug", - "test": "__ZEN_MOCK_UTC_TIME=2025-08-19T16:55:02.078Z jest", + "test": "cross-env __ZEN_MOCK_UTC_TIME=2025-08-19T16:55:02.078Z jest", "artifacts": "napi artifacts -d ../../artifacts", "prepublishOnly": "napi prepublish", "version": "napi version" diff --git a/bindings/nodejs/yarn.lock b/bindings/nodejs/yarn.lock index 9897d069..8296aa14 100644 --- a/bindings/nodejs/yarn.lock +++ b/bindings/nodejs/yarn.lock @@ -285,6 +285,11 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@epic-web/invariant@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@epic-web/invariant/-/invariant-1.0.0.tgz#1073e5dee6dd540410784990eb73e4acd25c9813" + integrity sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA== + "@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" @@ -2167,6 +2172,14 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cross-env@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-10.0.0.tgz#ba25823cfa1ed6af293dcded8796fa16cd162456" + integrity sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q== + dependencies: + "@epic-web/invariant" "^1.0.0" + cross-spawn "^7.0.6" + cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index a3885756..ef9b8542 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -4,7 +4,6 @@ build-backend = "maturin" [project] name = "zen-engine" -dynamic = ["version"] requires-python = ">=3.7" classifiers = [ "Programming Language :: Rust", From 61e6e68d7f3699baad6bde0521a406fdaafb5ec5 Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 22 Aug 2025 11:32:58 +0200 Subject: [PATCH 13/14] fix workflow --- .github/workflows/node.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/node.yaml b/.github/workflows/node.yaml index 4d409652..b52d274a 100644 --- a/.github/workflows/node.yaml +++ b/.github/workflows/node.yaml @@ -124,7 +124,7 @@ jobs: uses: actions/setup-node@v3 if: ${{ !matrix.settings.docker }} with: - node-version: 18 + node-version: 22 check-latest: true cache: yarn cache-dependency-path: 'bindings/nodejs/yarn.lock' @@ -191,7 +191,7 @@ jobs: target: 'aarch64-apple-darwin' - host: windows-latest target: 'x86_64-pc-windows-msvc' - node: [ '18', '20', '22' ] + node: [ '20', '22' ] runs-on: ${{ matrix.settings.host }} steps: @@ -457,7 +457,7 @@ jobs: - name: Setup node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 check-latest: true cache: yarn cache-dependency-path: 'bindings/nodejs/yarn.lock' From 15a1188a56992718fb7053e72e3f4a1644f07247 Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 22 Aug 2025 11:43:58 +0200 Subject: [PATCH 14/14] fix --- .github/workflows/node.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/node.yaml b/.github/workflows/node.yaml index b52d274a..eb6a6a64 100644 --- a/.github/workflows/node.yaml +++ b/.github/workflows/node.yaml @@ -111,7 +111,7 @@ jobs: yarn build --target aarch64-unknown-linux-musl /aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node - name: stable - ${{ matrix.settings.target }} - node@18 + name: stable - ${{ matrix.settings.target }} - node@22 runs-on: ${{ matrix.settings.host }} defaults: run: @@ -235,7 +235,7 @@ jobs: strategy: fail-fast: false matrix: - node: [ '18', '20', '22' ] + node: [ '20', '22' ] runs-on: ubuntu-latest steps: @@ -286,7 +286,7 @@ jobs: strategy: fail-fast: false matrix: - node: [ '18', '20', '22' ] + node: [ '20', '22' ] runs-on: ubuntu-latest steps: @@ -337,7 +337,7 @@ jobs: strategy: fail-fast: false matrix: - node: [ '18', '20', '22' ] + node: [ '20', '22' ] runs-on: ubuntu-latest steps: