diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml new file mode 100644 index 00000000..7454a77a --- /dev/null +++ b/.github/workflows/benchmark.yaml @@ -0,0 +1,124 @@ +name: Benchmark + +on: + release: + types: [ published ] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +env: + BENCH_ITERS: '500' + +jobs: + rust: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install Rust + run: rustup update stable + - uses: ./.github/actions/setup-rust + with: + shared-key: benchmark-rust + sccache: 'false' + - name: Build + run: cargo build --release -p zen-benchmark + - name: Run + run: ./target/release/zen-benchmark benchmark/manifest.json "$GITHUB_WORKSPACE/bench-rust.json" + - uses: actions/upload-artifact@v4 + with: + name: bench-rust + path: bench-rust.json + if-no-files-found: error + + node: + runs-on: ubuntu-latest + defaults: + run: + working-directory: bindings/nodejs + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 22 + cache: yarn + cache-dependency-path: 'bindings/nodejs/yarn.lock' + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: x86_64-unknown-linux-gnu + - uses: ./.github/actions/setup-rust + with: + shared-key: benchmark-node + sccache: 'false' + - run: yarn install --immutable --mode=skip-build + - run: yarn build + - name: Run + working-directory: ${{ github.workspace }} + run: node benchmark/node/bench.mjs "$GITHUB_WORKSPACE/bench-node.json" + - uses: actions/upload-artifact@v4 + with: + name: bench-node + path: bench-node.json + if-no-files-found: error + + python: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.13' + - name: Install Rust + run: rustup update stable + - uses: ./.github/actions/setup-rust + with: + shared-key: benchmark-python + sccache: 'false' + - run: pip install maturin + - name: Build + install wheel + run: | + maturin build --release --out dist -m bindings/python/Cargo.toml + pip install dist/*.whl + - name: Run + run: python benchmark/python/bench.py "$GITHUB_WORKSPACE/bench-python.json" + - uses: actions/upload-artifact@v4 + with: + name: bench-python + path: bench-python.json + if-no-files-found: error + + publish: + runs-on: ubuntu-latest + needs: [ rust, node, python ] + steps: + - uses: actions/checkout@v3 + - uses: actions/download-artifact@v4 + with: + path: results + merge-multiple: true + - name: Merge results + run: | + node -e ' + const fs = require("fs"); + const out = []; + for (const lang of ["rust", "node", "python"]) { + const r = JSON.parse(fs.readFileSync(`results/bench-${lang}.json`, "utf8")); + for (const e of r) out.push({ ...e, name: `${lang} ยท ${e.name}` }); + } + fs.writeFileSync("bench-all.json", JSON.stringify(out, null, 2)); + ' + - name: Store + publish + uses: benchmark-action/github-action-benchmark@v1 + with: + name: ZEN cross-language + tool: customSmallerIsBetter + output-file-path: bench-all.json + github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: true + alert-threshold: '150%' + comment-on-alert: true + fail-on-alert: false diff --git a/Cargo.lock b/Cargo.lock index a4a7e794..50d6e373 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4933,6 +4933,17 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zen-benchmark" +version = "0.0.0" +dependencies = [ + "serde", + "serde_json", + "tokio", + "zen-engine", + "zen-expression", +] + [[package]] name = "zen-engine" version = "0.55.1" diff --git a/Cargo.toml b/Cargo.toml index 8e5665f0..d803dd37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,8 @@ resolver = "2" members = [ "core/*", - "bindings/*" + "bindings/*", + "benchmark/rust" ] [workspace.dependencies] diff --git a/benchmark/.gitignore b/benchmark/.gitignore new file mode 100644 index 00000000..d7415703 --- /dev/null +++ b/benchmark/.gitignore @@ -0,0 +1,2 @@ +.venv/ +.dist/ diff --git a/benchmark/Makefile b/benchmark/Makefile new file mode 100644 index 00000000..5ac85731 --- /dev/null +++ b/benchmark/Makefile @@ -0,0 +1,41 @@ +BENCH_ITERS ?= 500 +export BENCH_ITERS + +ROOT := $(CURDIR)/.. +VENV := $(CURDIR)/.venv +PY := $(VENV)/bin/python +BIN := $(ROOT)/target/release/zen-benchmark + +.PHONY: all compare fixtures rust node python build-rust build-node build-python + +all: rust node python + +fixtures: + @node gen.mjs + +compare: + @node compare.mjs + +rust: build-rust + @printf '\n=== rust ===\n' + @$(BIN) manifest.json + +node: build-node + @printf '\n=== node ===\n' + @node node/bench.mjs + +python: build-python + @printf '\n=== python ===\n' + @$(PY) python/bench.py + +build-rust: + @cargo build --release -q -p zen-benchmark + +build-node: + @cd $(ROOT)/bindings/nodejs && yarn install --immutable --mode=skip-build && yarn build + +build-python: + @test -d $(VENV) || python3 -m venv $(VENV) + @$(PY) -m pip install --quiet --upgrade pip maturin + @rm -rf $(CURDIR)/.dist && $(PY) -m maturin build --release --out $(CURDIR)/.dist -m $(ROOT)/bindings/python/Cargo.toml + @$(PY) -m pip install --quiet --force-reinstall $(CURDIR)/.dist/*.whl diff --git a/benchmark/compare.mjs b/benchmark/compare.mjs new file mode 100644 index 00000000..817354d6 --- /dev/null +++ b/benchmark/compare.mjs @@ -0,0 +1,54 @@ +import { execSync, execFileSync } from 'node:child_process'; +import { readFileSync, mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const dir = path.dirname(fileURLToPath(import.meta.url)); +const root = path.join(dir, '..'); +const manifest = JSON.parse(readFileSync(path.join(dir, 'manifest.json'), 'utf8')); +const rowNames = manifest.flatMap((e) => [`${e.name} (${e.kind})`, `${e.name} (${e.kind}) +trace`]); + +const langs = [ + { key: 'rust', build: 'build-rust', cmd: path.join(root, 'target', 'release', 'zen-benchmark'), args: ['manifest.json'] }, + { key: 'node', build: 'build-node', cmd: process.execPath, args: [path.join(dir, 'node', 'bench.mjs')] }, + { key: 'python', build: 'build-python', cmd: path.join(dir, '.venv', 'bin', 'python'), args: [path.join(dir, 'python', 'bench.py')] }, +]; + +const tmp = mkdtempSync(path.join(tmpdir(), 'zen-bench-')); +const values = {}; +for (const lang of langs) { + try { + execSync(`make ${lang.build}`, { cwd: dir, stdio: 'inherit', env: process.env }); + const out = path.join(tmp, `${lang.key}.json`); + execFileSync(lang.cmd, [...lang.args, out], { cwd: dir, stdio: ['ignore', 'ignore', 'inherit'], env: process.env }); + const arr = JSON.parse(readFileSync(out, 'utf8')); + values[lang.key] = Object.fromEntries(arr.map((e) => [e.name, e.value])); + } catch (err) { + console.error(`! skipping ${lang.key}: ${err.message}`); + values[lang.key] = null; + } +} +rmSync(tmp, { recursive: true, force: true }); + +const NAME_W = 52; +const COL_W = 22; +const get = (key, name) => (values[key] ? values[key][name] : undefined); +const cell = (v, base) => { + if (v == null) return 'n/a'.padStart(COL_W); + const ns = `${Math.round(v)} ns`; + if (base == null) return ns.padStart(COL_W); + const mult = base === 0 ? '' : `${(v / base).toFixed(2)}x`; + return `${ns} ${mult}`.padStart(COL_W); +}; + +const header = `${'fixture'.padEnd(NAME_W)}${['rust', 'node', 'python'].map((l) => l.padStart(COL_W)).join('')}`; +console.log(''); +console.log(header); +console.log('-'.repeat(header.length)); +for (const name of rowNames) { + const r = get('rust', name); + console.log(`${name.padEnd(NAME_W)}${cell(r, null)}${cell(get('node', name), r)}${cell(get('python', name), r)}`); +} +console.log(''); +console.log('x = slowdown vs rust (rust is the baseline floor; lower is better)'); diff --git a/benchmark/fixtures/graphs/credit-limit-adjustment.json b/benchmark/fixtures/graphs/credit-limit-adjustment.json new file mode 100644 index 00000000..a2b9d4b5 --- /dev/null +++ b/benchmark/fixtures/graphs/credit-limit-adjustment.json @@ -0,0 +1 @@ +{"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/benchmark/fixtures/graphs/customer-eligibility-engine.json b/benchmark/fixtures/graphs/customer-eligibility-engine.json new file mode 100644 index 00000000..2d739309 --- /dev/null +++ b/benchmark/fixtures/graphs/customer-eligibility-engine.json @@ -0,0 +1 @@ +{"contentType":"application/vnd.gorules.decision","nodes":[{"type":"inputNode","id":"in","name":"request","content":{"schema":""},"position":{"x":2020,"y":120}},{"type":"expressionNode","id":"dailyStats","name":"dailyStats","content":{"expressions":[{"id":"dailyStats_e0","key":"cost","value":"dataGB * 0.5 + minutes * 0.01 + texts * 0.001"},{"id":"dailyStats_e1","key":"heavy","value":"dataGB > 2"}],"passThrough":true,"inputField":"usageHistory","outputPath":"daily","executionMode":"loop"},"position":{"x":2180,"y":120}},{"type":"decisionTableNode","id":"dailyTier","name":"dailyTier","content":{"hitPolicy":"first","inputs":[{"id":"i","name":"Cost","field":"cost"}],"outputs":[{"id":"o","name":"Tier","field":"usageTier"}],"rules":[{"_id":"r1","i":"> 5","o":"'high'"},{"_id":"r2","i":"> 2","o":"'medium'"},{"_id":"r3","i":"","o":"'low'"}],"passThrough":true,"inputField":"daily","outputPath":"dailyTiered","executionMode":"loop"},"position":{"x":2340,"y":120}},{"type":"expressionNode","id":"aggregate","name":"aggregate","content":{"expressions":[{"id":"aggregate_e0","key":"totalCost","value":"sum(map(daily, #.cost))"},{"id":"aggregate_e1","key":"heavyDays","value":"len(filter(daily, #.heavy))"},{"id":"aggregate_e2","key":"avgData","value":"sum(map(usageHistory, #.dataGB)) / len(usageHistory)"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":2500,"y":120}},{"type":"decisionTableNode","id":"accountStatus","name":"accountStatus","content":{"hitPolicy":"first","inputs":[{"id":"i1","name":"Age","field":"accountInfo.accountAge"},{"id":"i2","name":"Payment","field":"accountInfo.paymentHistory"}],"outputs":[{"id":"o1","name":"Status","field":"eligibility.accountStatus"},{"id":"o2","name":"Good","field":"eligibility.goodStanding"}],"rules":[{"_id":"r1","i1":">= 24","i2":"'excellent'","o1":"'excellent'","o2":"true"},{"_id":"r2","i1":">= 12","i2":"'excellent', 'good'","o1":"'good'","o2":"true"},{"_id":"r3","i1":">= 6","i2":"","o1":"'fair'","o2":"true"},{"_id":"r4","i1":"","i2":"","o1":"'review'","o2":"false"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":2660,"y":120}},{"type":"decisionTableNode","id":"loyaltyTier","name":"loyaltyTier","content":{"hitPolicy":"first","inputs":[{"id":"i1","name":"Age","field":"accountInfo.accountAge"},{"id":"i2","name":"Spend","field":"accountInfo.monthlySpend"}],"outputs":[{"id":"o1","name":"Tier","field":"eligibility.loyaltyTier"},{"id":"o2","name":"Discount","field":"eligibility.loyaltyDiscountPercent"}],"rules":[{"_id":"r1","i1":">= 36","i2":">= 120","o1":"'platinum'","o2":"20"},{"_id":"r2","i1":">= 24","i2":">= 80","o1":"'gold'","o2":"15"},{"_id":"r3","i1":">= 12","i2":">= 50","o1":"'silver'","o2":"10"},{"_id":"r4","i1":"","i2":"","o1":"'standard'","o2":"0"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":2820,"y":120}},{"type":"expressionNode","id":"specialOffers","name":"specialOffers","content":{"expressions":[{"id":"specialOffers_e0","key":"eligibility.specialOffers","value":"{ 'dataBooster': usageStats.dataUtilizationPercent > 80, 'familyPlan': len(customerProfile.devices) >= 3, 'loyaltyReward': eligibility.loyaltyTier in ['platinum', 'gold', 'silver'] }"},{"id":"specialOffers_e1","key":"eligibility.offerCount","value":"len(filter(values($.eligibility.specialOffers), # == true))"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":2980,"y":120}},{"type":"expressionNode","id":"replicate","name":"replicate","content":{"expressions":[{"id":"replicate_e0","key":"historyCopy","value":"usageHistory"},{"id":"replicate_e1","key":"dailyCopy","value":"daily"},{"id":"replicate_e2","key":"tieredCopy","value":"dailyTiered"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":3140,"y":120}}],"edges":[{"id":"edge0","type":"edge","sourceId":"in","targetId":"dailyStats"},{"id":"edge1","type":"edge","sourceId":"dailyStats","targetId":"dailyTier"},{"id":"edge2","type":"edge","sourceId":"dailyTier","targetId":"aggregate"},{"id":"edge3","type":"edge","sourceId":"aggregate","targetId":"accountStatus"},{"id":"edge4","type":"edge","sourceId":"accountStatus","targetId":"loyaltyTier"},{"id":"edge5","type":"edge","sourceId":"loyaltyTier","targetId":"specialOffers"},{"id":"edge6","type":"edge","sourceId":"specialOffers","targetId":"replicate"}]} \ No newline at end of file diff --git a/benchmark/fixtures/graphs/decision-table-discounts.json b/benchmark/fixtures/graphs/decision-table-discounts.json new file mode 100644 index 00000000..7b47ed92 --- /dev/null +++ b/benchmark/fixtures/graphs/decision-table-discounts.json @@ -0,0 +1 @@ +{"contentType":"application/vnd.gorules.decision","nodes":[{"id":"5eefa8a4-56a9-46b1-a265-7ddbddde3441","type":"inputNode","position":{"x":240,"y":280},"name":"Request"},{"id":"638d767d-ae08-4ba3-9db3-97c6c4e4c6f5","type":"decisionTableNode","position":{"x":520,"y":280},"name":"Discounts","content":{"hitPolicy":"collect","inputs":[{"id":"6fd35e3e-584b-4149-b4bf-5f2d258f40e7","type":"expression","field":"code","name":"Code"},{"id":"a1700de6-fe35-4cec-b66f-0897d2604a3f","name":"Order Date","type":"expression","field":"date(order.createdAt)"},{"id":"813dace4-0b55-4409-adb2-b4739a653302","type":"expression","field":"date(customer.joinDate)","name":"Customer Join Date"},{"id":"f34f2c8b-eba9-4ebe-aeec-384bce69e3aa","type":"expression","field":"len(customer.pastPurchases)","name":"Customer Past Purchases"}],"outputs":[{"field":"discount.percentage","id":"16d637be-1093-4468-b29f-236666bf2f26","name":"Discount Percentage","type":"expression"},{"id":"bccbb1bc-f0da-4b1e-b186-122ba4a193ac","type":"expression","field":"discount.flat","name":"Discount Flat"}],"rules":[{"_id":"eabd4e2e-5c14-4d4d-ada6-b3cdc547ae99","_description":"Welcome bonus of 15%","6fd35e3e-584b-4149-b4bf-5f2d258f40e7":"\"WELCOME_2023\"","a1700de6-fe35-4cec-b66f-0897d2604a3f":"","813dace4-0b55-4409-adb2-b4739a653302":"> date(\"2023-01-01\")","f34f2c8b-eba9-4ebe-aeec-384bce69e3aa":"0","16d637be-1093-4468-b29f-236666bf2f26":"15","bccbb1bc-f0da-4b1e-b186-122ba4a193ac":""},{"_id":"d80dee00-07a7-42fb-bc83-262eeee9fbdb","_description":"Recurring customer 25$ discount","6fd35e3e-584b-4149-b4bf-5f2d258f40e7":"\"BACK_TO_BACK\"","a1700de6-fe35-4cec-b66f-0897d2604a3f":"[date(\"2023-01-01\")..date(\"2023-02-01\")]","813dace4-0b55-4409-adb2-b4739a653302":"","f34f2c8b-eba9-4ebe-aeec-384bce69e3aa":"> 10","16d637be-1093-4468-b29f-236666bf2f26":"","bccbb1bc-f0da-4b1e-b186-122ba4a193ac":"25"},{"_id":"fcfae4b3-5c86-4efe-91cd-ca4bc1fa7c7c","_description":"Old customer 10%","6fd35e3e-584b-4149-b4bf-5f2d258f40e7":"\"EARLY_BIRD\"","a1700de6-fe35-4cec-b66f-0897d2604a3f":"","813dace4-0b55-4409-adb2-b4739a653302":"< date(\"2020-01-01\")","f34f2c8b-eba9-4ebe-aeec-384bce69e3aa":"","16d637be-1093-4468-b29f-236666bf2f26":"10","bccbb1bc-f0da-4b1e-b186-122ba4a193ac":""}]}},{"id":"c87d26e6-f3a2-47ad-9310-cbd1899cc68a","type":"outputNode","position":{"x":830,"y":280},"name":"Response"}],"edges":[{"id":"3b07d6c5-6949-4e5d-a8c6-f5cf44dbba0a","sourceId":"5eefa8a4-56a9-46b1-a265-7ddbddde3441","type":"edge","targetId":"638d767d-ae08-4ba3-9db3-97c6c4e4c6f5"},{"id":"69e558e4-4c20-4a53-9230-c068ebb19830","sourceId":"638d767d-ae08-4ba3-9db3-97c6c4e4c6f5","type":"edge","targetId":"c87d26e6-f3a2-47ad-9310-cbd1899cc68a"}]} \ No newline at end of file diff --git a/benchmark/fixtures/graphs/dynamic-shipping-cost-calculator.json b/benchmark/fixtures/graphs/dynamic-shipping-cost-calculator.json new file mode 100644 index 00000000..79ad87a2 --- /dev/null +++ b/benchmark/fixtures/graphs/dynamic-shipping-cost-calculator.json @@ -0,0 +1 @@ +{"contentType":"application/vnd.gorules.decision","nodes":[{"type":"inputNode","id":"in","name":"request","content":{"schema":""},"position":{"x":1060,"y":120}},{"type":"expressionNode","id":"dims","name":"dims","content":{"expressions":[{"id":"dims_e0","key":"dimWeight","value":"(length * width * height) / 5000"},{"id":"dims_e1","key":"effWeight","value":"max([weight, (length * width * height) / 5000])"},{"id":"dims_e2","key":"distFactor","value":"distance / 100"}],"passThrough":true,"inputField":"shipments","outputPath":"computed","executionMode":"loop"},"position":{"x":1220,"y":120}},{"type":"decisionTableNode","id":"baseRate","name":"baseRate","content":{"hitPolicy":"first","inputs":[{"id":"i1","name":"Type","field":"shippingType"},{"id":"i2","name":"Weight","field":"effWeight"}],"outputs":[{"id":"o1","name":"Base","field":"baseRate"}],"rules":[{"_id":"r1","i1":"'standard'","i2":"< 20","o1":"10"},{"_id":"r2","i1":"'standard'","i2":"","o1":"20"},{"_id":"r3","i1":"'express'","i2":"< 20","o1":"20"},{"_id":"r4","i1":"'express'","i2":"","o1":"35"},{"_id":"r5","i1":"'priority'","i2":"","o1":"50"},{"_id":"r6","i1":"","i2":"","o1":"15"}],"passThrough":true,"inputField":"computed","outputPath":"rated","executionMode":"loop"},"position":{"x":1380,"y":120}},{"type":"decisionTableNode","id":"finalPrice","name":"finalPrice","content":{"hitPolicy":"first","inputs":[{"id":"i1","name":"Tier","field":"customerTier"}],"outputs":[{"id":"o1","name":"Final","field":"finalPrice"}],"rules":[{"_id":"r1","i1":"'gold'","o1":"baseRate * (effWeight / weight) * (1 + distFactor * 0.1) * 0.9"},{"_id":"r2","i1":"'silver'","o1":"baseRate * (effWeight / weight) * (1 + distFactor * 0.1) * 0.95"},{"_id":"r3","i1":"","o1":"baseRate * (effWeight / weight) * (1 + distFactor * 0.1)"}],"passThrough":true,"inputField":"rated","outputPath":"priced","executionMode":"loop"},"position":{"x":1540,"y":120}},{"type":"expressionNode","id":"replicate","name":"replicate","content":{"expressions":[{"id":"replicate_e0","key":"shipmentsCopy","value":"shipments"},{"id":"replicate_e1","key":"computedCopy","value":"computed"},{"id":"replicate_e2","key":"pricedCopy","value":"priced"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":1700,"y":120}},{"type":"expressionNode","id":"totals","name":"totals","content":{"expressions":[{"id":"totals_e0","key":"totalPrice","value":"sum(map(priced, #.finalPrice))"},{"id":"totals_e1","key":"count","value":"len(shipments)"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":1860,"y":120}}],"edges":[{"id":"edge0","type":"edge","sourceId":"in","targetId":"dims"},{"id":"edge1","type":"edge","sourceId":"dims","targetId":"baseRate"},{"id":"edge2","type":"edge","sourceId":"baseRate","targetId":"finalPrice"},{"id":"edge3","type":"edge","sourceId":"finalPrice","targetId":"replicate"},{"id":"edge4","type":"edge","sourceId":"replicate","targetId":"totals"}]} \ No newline at end of file diff --git a/benchmark/fixtures/graphs/expression-table-map.json b/benchmark/fixtures/graphs/expression-table-map.json new file mode 100644 index 00000000..562ed42d --- /dev/null +++ b/benchmark/fixtures/graphs/expression-table-map.json @@ -0,0 +1 @@ +{"contentType":"application/vnd.gorules.decision","nodes":[{"type":"inputNode","id":"in","name":"request","content":{"schema":""},"position":{"x":260,"y":120}},{"type":"expressionNode","id":"enrich","name":"enrich","content":{"expressions":[{"id":"enrich_e0","key":"subtotal","value":"amount * qty"},{"id":"enrich_e1","key":"premium","value":"amount > 40 and group == 'accessories'"}],"passThrough":true,"inputField":"items","outputPath":"enriched","executionMode":"loop"},"position":{"x":420,"y":120}},{"type":"decisionTableNode","id":"classify","name":"classify","content":{"hitPolicy":"first","inputs":[{"id":"ci","name":"Subtotal","field":"subtotal"}],"outputs":[{"id":"co","name":"Discount","field":"discount"}],"rules":[{"_id":"r1","ci":"> 1000","co":"15"},{"_id":"r2","ci":"> 500","co":"10"},{"_id":"r3","ci":"> 100","co":"5"},{"_id":"r4","ci":"","co":"0"}],"passThrough":true,"inputField":"enriched","outputPath":"classified","executionMode":"loop"},"position":{"x":580,"y":120}},{"type":"expressionNode","id":"replicate","name":"replicate","content":{"expressions":[{"id":"replicate_e0","key":"allItems","value":"items"},{"id":"replicate_e1","key":"enrichedCopy","value":"enriched"},{"id":"replicate_e2","key":"classifiedCopy","value":"classified"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":740,"y":120}},{"type":"expressionNode","id":"totals","name":"totals","content":{"expressions":[{"id":"totals_e0","key":"grandTotal","value":"sum(map(enriched, #.subtotal))"},{"id":"totals_e1","key":"itemCount","value":"len(items)"},{"id":"totals_e2","key":"premiumCount","value":"len(filter(enriched, #.premium))"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":900,"y":120}}],"edges":[{"id":"edge0","type":"edge","sourceId":"in","targetId":"enrich"},{"id":"edge1","type":"edge","sourceId":"enrich","targetId":"classify"},{"id":"edge2","type":"edge","sourceId":"classify","targetId":"replicate"},{"id":"edge3","type":"edge","sourceId":"replicate","targetId":"totals"}]} \ No newline at end of file diff --git a/benchmark/fixtures/policies/expression-chain.json b/benchmark/fixtures/policies/expression-chain.json new file mode 100644 index 00000000..8cd3491e --- /dev/null +++ b/benchmark/fixtures/policies/expression-chain.json @@ -0,0 +1 @@ +{"blocks":[{"id":"dm","type":"dataModel","props":{"data":{"name":"customer","properties":[{"id":"p0","name":"amounts","type":"number","array":true,"optional":false},{"id":"p1","name":"label","type":"string","array":false,"optional":false}]}},"children":[]},{"id":"e1","type":"expression","props":{"data":{"key":"customer.positive","value":"filter(customer.amounts, # > 0)"}}},{"id":"e2","type":"expression","props":{"data":{"key":"customer.negatives","value":"filter(customer.amounts, # < 0)"}}},{"id":"e3","type":"expression","props":{"data":{"key":"customer.doubled","value":"map(customer.amounts, # * 2)"}}},{"id":"e4","type":"expression","props":{"data":{"key":"customer.squared","value":"map(customer.amounts, # * #)"}}},{"id":"e5","type":"expression","props":{"data":{"key":"customer.total","value":"sum(customer.positive)"}}},{"id":"e6","type":"expression","props":{"data":{"key":"customer.negTotal","value":"sum(customer.negatives)"}}},{"id":"e7","type":"expression","props":{"data":{"key":"customer.net","value":"customer.total + customer.negTotal"}}},{"id":"e8","type":"expression","props":{"data":{"key":"customer.posCount","value":"len(customer.positive)"}}},{"id":"e9","type":"expression","props":{"data":{"key":"customer.avg","value":"customer.net / len(customer.amounts)"}}},{"id":"e10","type":"expression","props":{"data":{"key":"customer.maxVal","value":"max(customer.amounts)"}}},{"id":"e11","type":"expression","props":{"data":{"key":"customer.minVal","value":"min(customer.amounts)"}}},{"id":"a1","type":"assertion","props":{"data":{"output":"customer.bigSpender","conditions":[{"id":"a1c","expression":"customer.total > 1000","operator":"and","depth":0}]}},"children":[]},{"id":"a2","type":"assertion","props":{"data":{"output":"customer.balanced","conditions":[{"id":"a2c","expression":"customer.net > 0","operator":"and","depth":0}]}},"children":[]},{"id":"a3","type":"assertion","props":{"data":{"output":"customer.volatile","conditions":[{"id":"a3c","expression":"customer.maxVal - customer.minVal > 50","operator":"and","depth":0}]}},"children":[]}]} \ No newline at end of file diff --git a/benchmark/fixtures/policies/expression.json b/benchmark/fixtures/policies/expression.json new file mode 100644 index 00000000..7b2356eb --- /dev/null +++ b/benchmark/fixtures/policies/expression.json @@ -0,0 +1 @@ +{"blocks":[{"id":"dm","type":"dataModel","props":{"data":{"name":"customer","properties":[{"id":"p0","name":"age","type":"number","array":false,"optional":false},{"id":"p1","name":"income","type":"number","array":false,"optional":false}]}},"children":[]},{"id":"e1","type":"expression","props":{"data":{"key":"customer.score","value":"customer.age + customer.income / 1000"}}},{"id":"a1","type":"assertion","props":{"data":{"output":"customer.eligible","conditions":[{"id":"a1c","expression":"customer.score > 50","operator":"and","depth":0}]}},"children":[]}]} \ No newline at end of file diff --git a/benchmark/fixtures/policies/match.json b/benchmark/fixtures/policies/match.json new file mode 100644 index 00000000..686fbdce --- /dev/null +++ b/benchmark/fixtures/policies/match.json @@ -0,0 +1 @@ +{"blocks":[{"id":"dm","type":"dataModel","props":{"data":{"name":"customer","properties":[{"id":"p0","name":"score","type":"number","array":false,"optional":false}]}},"children":[]},{"id":"m1","type":"match","props":{"data":{"key":"customer.tier","arms":[{"id":"a1","condition":"customer.score >= 80","value":"\"gold\""},{"id":"a2","condition":"customer.score >= 50","value":"\"silver\""},{"id":"a3","condition":"","value":"\"bronze\""}]}}}]} \ No newline at end of file diff --git a/benchmark/fixtures/policies/multi-assertion.json b/benchmark/fixtures/policies/multi-assertion.json new file mode 100644 index 00000000..85646aeb --- /dev/null +++ b/benchmark/fixtures/policies/multi-assertion.json @@ -0,0 +1 @@ +{"blocks":[{"id":"dm","type":"dataModel","props":{"data":{"name":"customer","properties":[{"id":"p0","name":"age","type":"number","array":false,"optional":false},{"id":"p1","name":"income","type":"number","array":false,"optional":false},{"id":"p2","name":"employmentYears","type":"number","array":false,"optional":false},{"id":"p3","name":"scores","type":"number","array":true,"optional":false}]}},"children":[]},{"id":"s1","type":"expression","props":{"data":{"key":"customer.scoreSum","value":"sum(customer.scores)"}}},{"id":"s2","type":"expression","props":{"data":{"key":"customer.scoreAvg","value":"customer.scoreSum / len(customer.scores)"}}},{"id":"s3","type":"expression","props":{"data":{"key":"customer.highScores","value":"filter(customer.scores, # > 50)"}}},{"id":"s4","type":"expression","props":{"data":{"key":"customer.scaled","value":"map(customer.scores, # * 1.5)"}}},{"id":"a0","type":"assertion","props":{"data":{"output":"customer.flag0","conditions":[{"id":"a0c","expression":"customer.scoreAvg >= 0","operator":"and","depth":0}]}},"children":[]},{"id":"a1","type":"assertion","props":{"data":{"output":"customer.flag1","conditions":[{"id":"a1c","expression":"customer.scoreAvg >= 1","operator":"and","depth":0}]}},"children":[]},{"id":"a2","type":"assertion","props":{"data":{"output":"customer.flag2","conditions":[{"id":"a2c","expression":"customer.scoreAvg >= 2","operator":"and","depth":0}]}},"children":[]},{"id":"a3","type":"assertion","props":{"data":{"output":"customer.flag3","conditions":[{"id":"a3c","expression":"customer.scoreAvg >= 3","operator":"and","depth":0}]}},"children":[]},{"id":"a4","type":"assertion","props":{"data":{"output":"customer.flag4","conditions":[{"id":"a4c","expression":"customer.scoreAvg >= 4","operator":"and","depth":0}]}},"children":[]},{"id":"a5","type":"assertion","props":{"data":{"output":"customer.flag5","conditions":[{"id":"a5c","expression":"customer.scoreAvg >= 5","operator":"and","depth":0}]}},"children":[]},{"id":"a6","type":"assertion","props":{"data":{"output":"customer.flag6","conditions":[{"id":"a6c","expression":"customer.scoreAvg >= 6","operator":"and","depth":0}]}},"children":[]},{"id":"a7","type":"assertion","props":{"data":{"output":"customer.flag7","conditions":[{"id":"a7c","expression":"customer.scoreAvg >= 7","operator":"and","depth":0}]}},"children":[]},{"id":"a8","type":"assertion","props":{"data":{"output":"customer.flag8","conditions":[{"id":"a8c","expression":"customer.scoreAvg >= 8","operator":"and","depth":0}]}},"children":[]},{"id":"a9","type":"assertion","props":{"data":{"output":"customer.flag9","conditions":[{"id":"a9c","expression":"customer.scoreAvg >= 9","operator":"and","depth":0}]}},"children":[]},{"id":"a10","type":"assertion","props":{"data":{"output":"customer.flag10","conditions":[{"id":"a10c","expression":"customer.scoreAvg >= 10","operator":"and","depth":0}]}},"children":[]},{"id":"a11","type":"assertion","props":{"data":{"output":"customer.flag11","conditions":[{"id":"a11c","expression":"customer.scoreAvg >= 11","operator":"and","depth":0}]}},"children":[]},{"id":"a12","type":"assertion","props":{"data":{"output":"customer.flag12","conditions":[{"id":"a12c","expression":"customer.scoreAvg >= 12","operator":"and","depth":0}]}},"children":[]},{"id":"a13","type":"assertion","props":{"data":{"output":"customer.flag13","conditions":[{"id":"a13c","expression":"customer.scoreAvg >= 13","operator":"and","depth":0}]}},"children":[]},{"id":"a14","type":"assertion","props":{"data":{"output":"customer.flag14","conditions":[{"id":"a14c","expression":"customer.scoreAvg >= 14","operator":"and","depth":0}]}},"children":[]},{"id":"a15","type":"assertion","props":{"data":{"output":"customer.flag15","conditions":[{"id":"a15c","expression":"customer.scoreAvg >= 15","operator":"and","depth":0}]}},"children":[]},{"id":"a16","type":"assertion","props":{"data":{"output":"customer.flag16","conditions":[{"id":"a16c","expression":"customer.scoreAvg >= 16","operator":"and","depth":0}]}},"children":[]},{"id":"a17","type":"assertion","props":{"data":{"output":"customer.flag17","conditions":[{"id":"a17c","expression":"customer.scoreAvg >= 17","operator":"and","depth":0}]}},"children":[]},{"id":"a18","type":"assertion","props":{"data":{"output":"customer.flag18","conditions":[{"id":"a18c","expression":"customer.scoreAvg >= 18","operator":"and","depth":0}]}},"children":[]},{"id":"a19","type":"assertion","props":{"data":{"output":"customer.flag19","conditions":[{"id":"a19c","expression":"customer.scoreAvg >= 19","operator":"and","depth":0}]}},"children":[]},{"id":"a20","type":"assertion","props":{"data":{"output":"customer.flag20","conditions":[{"id":"a20c","expression":"customer.scoreAvg >= 20","operator":"and","depth":0}]}},"children":[]},{"id":"a21","type":"assertion","props":{"data":{"output":"customer.flag21","conditions":[{"id":"a21c","expression":"customer.scoreAvg >= 21","operator":"and","depth":0}]}},"children":[]},{"id":"a22","type":"assertion","props":{"data":{"output":"customer.flag22","conditions":[{"id":"a22c","expression":"customer.scoreAvg >= 22","operator":"and","depth":0}]}},"children":[]},{"id":"a23","type":"assertion","props":{"data":{"output":"customer.flag23","conditions":[{"id":"a23c","expression":"customer.scoreAvg >= 23","operator":"and","depth":0}]}},"children":[]},{"id":"a24","type":"assertion","props":{"data":{"output":"customer.flag24","conditions":[{"id":"a24c","expression":"customer.scoreAvg >= 24","operator":"and","depth":0}]}},"children":[]},{"id":"a25","type":"assertion","props":{"data":{"output":"customer.flag25","conditions":[{"id":"a25c","expression":"customer.scoreAvg >= 25","operator":"and","depth":0}]}},"children":[]},{"id":"a26","type":"assertion","props":{"data":{"output":"customer.flag26","conditions":[{"id":"a26c","expression":"customer.scoreAvg >= 26","operator":"and","depth":0}]}},"children":[]},{"id":"a27","type":"assertion","props":{"data":{"output":"customer.flag27","conditions":[{"id":"a27c","expression":"customer.scoreAvg >= 27","operator":"and","depth":0}]}},"children":[]},{"id":"a28","type":"assertion","props":{"data":{"output":"customer.flag28","conditions":[{"id":"a28c","expression":"customer.scoreAvg >= 28","operator":"and","depth":0}]}},"children":[]},{"id":"a29","type":"assertion","props":{"data":{"output":"customer.flag29","conditions":[{"id":"a29c","expression":"customer.scoreAvg >= 29","operator":"and","depth":0}]}},"children":[]}]} \ No newline at end of file diff --git a/benchmark/fixtures/policies/simple-assertion.json b/benchmark/fixtures/policies/simple-assertion.json new file mode 100644 index 00000000..6e76a719 --- /dev/null +++ b/benchmark/fixtures/policies/simple-assertion.json @@ -0,0 +1 @@ +{"blocks":[{"id":"dm","type":"dataModel","props":{"data":{"name":"customer","properties":[{"id":"p0","name":"age","type":"number","array":false,"optional":false}]}},"children":[]},{"id":"a1","type":"assertion","props":{"data":{"output":"customer.isAdult","conditions":[{"id":"a1c","expression":"customer.age >= 18","operator":"and","depth":0}]}},"children":[]}]} \ No newline at end of file diff --git a/benchmark/gen.mjs b/benchmark/gen.mjs new file mode 100644 index 00000000..c5b97f31 --- /dev/null +++ b/benchmark/gen.mjs @@ -0,0 +1,328 @@ +import { writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const dir = path.dirname(fileURLToPath(import.meta.url)); +const fixtures = path.join(dir, 'fixtures'); + +const ITEMS = 250; +const DAYS = 200; +const SHIPMENTS = 150; +const AMOUNTS = 600; +const SCORES = 300; +const ASSERTIONS = 30; + +const range = (n) => Array.from({ length: n }, (_, i) => i); + +let x = 100; +const pos = () => ({ x: (x += 160), y: 120 }); + +const inputNode = (id) => ({ type: 'inputNode', id, name: 'request', content: { schema: '' }, position: pos() }); + +const exprNode = (id, name, exprs, transform = {}) => ({ + type: 'expressionNode', + id, + name, + content: { + expressions: exprs.map(([key, value], i) => ({ id: `${id}_e${i}`, key, value })), + passThrough: true, + inputField: null, + outputPath: null, + executionMode: 'single', + ...transform, + }, + position: pos(), +}); + +const tableNode = (id, name, inputs, outputs, rules, transform = {}) => ({ + type: 'decisionTableNode', + id, + name, + content: { + hitPolicy: 'first', + inputs, + outputs, + rules, + passThrough: true, + inputField: null, + outputPath: null, + executionMode: 'single', + ...transform, + }, + position: pos(), +}); + +const graph = (nodes) => ({ + contentType: 'application/vnd.gorules.decision', + nodes, + edges: nodes.slice(1).map((n, i) => ({ id: `edge${i}`, type: 'edge', sourceId: nodes[i].id, targetId: n.id })), +}); + +const dataModel = (name, props) => ({ + id: 'dm', + type: 'dataModel', + props: { data: { name, properties: props.map((p, i) => ({ id: `p${i}`, name: p.name, type: p.type, array: !!p.array, optional: !!p.optional })) } }, + children: [], +}); + +const expr = (id, key, value) => ({ id, type: 'expression', props: { data: { key, value } } }); + +const assertion = (id, output, expression) => ({ + id, + type: 'assertion', + props: { data: { output, conditions: [{ id: `${id}c`, expression, operator: 'and', depth: 0 }] } }, + children: [], +}); + +const expressionTableMap = graph([ + inputNode('in'), + exprNode('enrich', 'enrich', [ + ['subtotal', 'amount * qty'], + ['premium', "amount > 40 and group == 'accessories'"], + ], { inputField: 'items', outputPath: 'enriched', executionMode: 'loop' }), + tableNode('classify', 'classify', + [{ id: 'ci', name: 'Subtotal', field: 'subtotal' }], + [{ id: 'co', name: 'Discount', field: 'discount' }], + [ + { _id: 'r1', ci: '> 1000', co: '15' }, + { _id: 'r2', ci: '> 500', co: '10' }, + { _id: 'r3', ci: '> 100', co: '5' }, + { _id: 'r4', ci: '', co: '0' }, + ], + { inputField: 'enriched', outputPath: 'classified', executionMode: 'loop' }), + exprNode('replicate', 'replicate', [ + ['allItems', 'items'], + ['enrichedCopy', 'enriched'], + ['classifiedCopy', 'classified'], + ]), + exprNode('totals', 'totals', [ + ['grandTotal', 'sum(map(enriched, #.subtotal))'], + ['itemCount', 'len(items)'], + ['premiumCount', 'len(filter(enriched, #.premium))'], + ]), +]); + +const dynamicShipping = graph([ + inputNode('in'), + exprNode('dims', 'dims', [ + ['dimWeight', '(length * width * height) / 5000'], + ['effWeight', 'max([weight, (length * width * height) / 5000])'], + ['distFactor', 'distance / 100'], + ], { inputField: 'shipments', outputPath: 'computed', executionMode: 'loop' }), + tableNode('baseRate', 'baseRate', + [ + { id: 'i1', name: 'Type', field: 'shippingType' }, + { id: 'i2', name: 'Weight', field: 'effWeight' }, + ], + [{ id: 'o1', name: 'Base', field: 'baseRate' }], + [ + { _id: 'r1', i1: "'standard'", i2: '< 20', o1: '10' }, + { _id: 'r2', i1: "'standard'", i2: '', o1: '20' }, + { _id: 'r3', i1: "'express'", i2: '< 20', o1: '20' }, + { _id: 'r4', i1: "'express'", i2: '', o1: '35' }, + { _id: 'r5', i1: "'priority'", i2: '', o1: '50' }, + { _id: 'r6', i1: '', i2: '', o1: '15' }, + ], + { inputField: 'computed', outputPath: 'rated', executionMode: 'loop' }), + tableNode('finalPrice', 'finalPrice', + [{ id: 'i1', name: 'Tier', field: 'customerTier' }], + [{ id: 'o1', name: 'Final', field: 'finalPrice' }], + [ + { _id: 'r1', i1: "'gold'", o1: 'baseRate * (effWeight / weight) * (1 + distFactor * 0.1) * 0.9' }, + { _id: 'r2', i1: "'silver'", o1: 'baseRate * (effWeight / weight) * (1 + distFactor * 0.1) * 0.95' }, + { _id: 'r3', i1: '', o1: 'baseRate * (effWeight / weight) * (1 + distFactor * 0.1)' }, + ], + { inputField: 'rated', outputPath: 'priced', executionMode: 'loop' }), + exprNode('replicate', 'replicate', [ + ['shipmentsCopy', 'shipments'], + ['computedCopy', 'computed'], + ['pricedCopy', 'priced'], + ]), + exprNode('totals', 'totals', [ + ['totalPrice', 'sum(map(priced, #.finalPrice))'], + ['count', 'len(shipments)'], + ]), +]); + +const customerEligibility = graph([ + inputNode('in'), + exprNode('dailyStats', 'dailyStats', [ + ['cost', 'dataGB * 0.5 + minutes * 0.01 + texts * 0.001'], + ['heavy', 'dataGB > 2'], + ], { inputField: 'usageHistory', outputPath: 'daily', executionMode: 'loop' }), + tableNode('dailyTier', 'dailyTier', + [{ id: 'i', name: 'Cost', field: 'cost' }], + [{ id: 'o', name: 'Tier', field: 'usageTier' }], + [ + { _id: 'r1', i: '> 5', o: "'high'" }, + { _id: 'r2', i: '> 2', o: "'medium'" }, + { _id: 'r3', i: '', o: "'low'" }, + ], + { inputField: 'daily', outputPath: 'dailyTiered', executionMode: 'loop' }), + exprNode('aggregate', 'aggregate', [ + ['totalCost', 'sum(map(daily, #.cost))'], + ['heavyDays', 'len(filter(daily, #.heavy))'], + ['avgData', 'sum(map(usageHistory, #.dataGB)) / len(usageHistory)'], + ]), + tableNode('accountStatus', 'accountStatus', + [ + { id: 'i1', name: 'Age', field: 'accountInfo.accountAge' }, + { id: 'i2', name: 'Payment', field: 'accountInfo.paymentHistory' }, + ], + [ + { id: 'o1', name: 'Status', field: 'eligibility.accountStatus' }, + { id: 'o2', name: 'Good', field: 'eligibility.goodStanding' }, + ], + [ + { _id: 'r1', i1: '>= 24', i2: "'excellent'", o1: "'excellent'", o2: 'true' }, + { _id: 'r2', i1: '>= 12', i2: "'excellent', 'good'", o1: "'good'", o2: 'true' }, + { _id: 'r3', i1: '>= 6', i2: '', o1: "'fair'", o2: 'true' }, + { _id: 'r4', i1: '', i2: '', o1: "'review'", o2: 'false' }, + ]), + tableNode('loyaltyTier', 'loyaltyTier', + [ + { id: 'i1', name: 'Age', field: 'accountInfo.accountAge' }, + { id: 'i2', name: 'Spend', field: 'accountInfo.monthlySpend' }, + ], + [ + { id: 'o1', name: 'Tier', field: 'eligibility.loyaltyTier' }, + { id: 'o2', name: 'Discount', field: 'eligibility.loyaltyDiscountPercent' }, + ], + [ + { _id: 'r1', i1: '>= 36', i2: '>= 120', o1: "'platinum'", o2: '20' }, + { _id: 'r2', i1: '>= 24', i2: '>= 80', o1: "'gold'", o2: '15' }, + { _id: 'r3', i1: '>= 12', i2: '>= 50', o1: "'silver'", o2: '10' }, + { _id: 'r4', i1: '', i2: '', o1: "'standard'", o2: '0' }, + ]), + exprNode('specialOffers', 'specialOffers', [ + ['eligibility.specialOffers', "{ 'dataBooster': usageStats.dataUtilizationPercent > 80, 'familyPlan': len(customerProfile.devices) >= 3, 'loyaltyReward': eligibility.loyaltyTier in ['platinum', 'gold', 'silver'] }"], + ['eligibility.offerCount', 'len(filter(values($.eligibility.specialOffers), # == true))'], + ]), + exprNode('replicate', 'replicate', [ + ['historyCopy', 'usageHistory'], + ['dailyCopy', 'daily'], + ['tieredCopy', 'dailyTiered'], + ]), +]); + +const expressionChain = { + blocks: [ + dataModel('customer', [ + { name: 'amounts', type: 'number', array: true }, + { name: 'label', type: 'string' }, + ]), + expr('e1', 'customer.positive', 'filter(customer.amounts, # > 0)'), + expr('e2', 'customer.negatives', 'filter(customer.amounts, # < 0)'), + expr('e3', 'customer.doubled', 'map(customer.amounts, # * 2)'), + expr('e4', 'customer.squared', 'map(customer.amounts, # * #)'), + expr('e5', 'customer.total', 'sum(customer.positive)'), + expr('e6', 'customer.negTotal', 'sum(customer.negatives)'), + expr('e7', 'customer.net', 'customer.total + customer.negTotal'), + expr('e8', 'customer.posCount', 'len(customer.positive)'), + expr('e9', 'customer.avg', 'customer.net / len(customer.amounts)'), + expr('e10', 'customer.maxVal', 'max(customer.amounts)'), + expr('e11', 'customer.minVal', 'min(customer.amounts)'), + assertion('a1', 'customer.bigSpender', 'customer.total > 1000'), + assertion('a2', 'customer.balanced', 'customer.net > 0'), + assertion('a3', 'customer.volatile', 'customer.maxVal - customer.minVal > 50'), + ], +}; + +const multiAssertion = { + blocks: [ + dataModel('customer', [ + { name: 'age', type: 'number' }, + { name: 'income', type: 'number' }, + { name: 'employmentYears', type: 'number' }, + { name: 'scores', type: 'number', array: true }, + ]), + expr('s1', 'customer.scoreSum', 'sum(customer.scores)'), + expr('s2', 'customer.scoreAvg', 'customer.scoreSum / len(customer.scores)'), + expr('s3', 'customer.highScores', 'filter(customer.scores, # > 50)'), + expr('s4', 'customer.scaled', 'map(customer.scores, # * 1.5)'), + ...range(ASSERTIONS).map((i) => assertion(`a${i}`, `customer.flag${i}`, `customer.scoreAvg >= ${i}`)), + ], +}; + +const manifest = [ + { + name: 'decision-table-discounts', + kind: 'graph', + file: 'graphs/decision-table-discounts.json', + input: { code: 'WELCOME_2023', order: { createdAt: '2023-01-15' }, customer: { joinDate: '2023-02-01', pastPurchases: [] } }, + }, + { + name: 'expression-table-map', + kind: 'graph', + file: 'graphs/expression-table-map.json', + input: { + customer: { name: 'John Doe', country: 'US' }, + items: range(ITEMS).map((i) => ({ name: `item${i}`, amount: 10 + (i % 90), group: i % 3 === 0 ? 'accessories' : 'electronics', qty: 1 + (i % 5) })), + }, + }, + { + name: 'credit-limit-adjustment', + kind: 'graph', + file: 'graphs/credit-limit-adjustment.json', + 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 }, + }, + }, + }, + { + name: 'dynamic-shipping-cost-calculator', + kind: 'graph', + file: 'graphs/dynamic-shipping-cost-calculator.json', + input: { + shipments: range(SHIPMENTS).map((i) => ({ + weight: 5 + (i % 40), + length: 20 + (i % 30), + width: 15 + (i % 20), + height: 10 + (i % 15), + distance: 50 + (i % 500), + shippingType: ['standard', 'express', 'priority'][i % 3], + customerTier: ['gold', 'silver', 'standard'][i % 3], + })), + }, + }, + { + name: 'customer-eligibility-engine', + kind: 'graph', + file: 'graphs/customer-eligibility-engine.json', + input: { + 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 }, + usageHistory: range(DAYS).map((d) => ({ day: d, dataGB: 1 + (d % 5), minutes: 100 + (d % 200), texts: 10 + (d % 50) })), + }, + }, + { name: 'simple-assertion', kind: 'policy', file: 'policies/simple-assertion.json', input: { customer: { age: 30 } } }, + { name: 'expression', kind: 'policy', file: 'policies/expression.json', input: { customer: { age: 35, income: 60000 } } }, + { + name: 'multi-assertion', + kind: 'policy', + file: 'policies/multi-assertion.json', + input: { customer: { age: 40, income: 60000, employmentYears: 5, scores: range(SCORES).map((i) => (i * 13) % 100) } }, + }, + { + name: 'expression-chain', + kind: 'policy', + file: 'policies/expression-chain.json', + input: { customer: { amounts: range(AMOUNTS).map((i) => ((i * 7) % 41) - 20), label: 'batch' } }, + }, + { name: 'match', kind: 'policy', file: 'policies/match.json', input: { customer: { score: 85 } } }, +]; + +writeFileSync(path.join(fixtures, 'graphs', 'expression-table-map.json'), JSON.stringify(expressionTableMap)); +writeFileSync(path.join(fixtures, 'graphs', 'dynamic-shipping-cost-calculator.json'), JSON.stringify(dynamicShipping)); +writeFileSync(path.join(fixtures, 'graphs', 'customer-eligibility-engine.json'), JSON.stringify(customerEligibility)); +writeFileSync(path.join(fixtures, 'policies', 'expression-chain.json'), JSON.stringify(expressionChain)); +writeFileSync(path.join(fixtures, 'policies', 'multi-assertion.json'), JSON.stringify(multiAssertion)); +writeFileSync(path.join(dir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n'); + +console.log('generated 5 heavy fixtures + manifest.json'); diff --git a/benchmark/manifest.json b/benchmark/manifest.json new file mode 100644 index 00000000..3fc35bf9 --- /dev/null +++ b/benchmark/manifest.json @@ -0,0 +1,5105 @@ +[ + { + "name": "decision-table-discounts", + "kind": "graph", + "file": "graphs/decision-table-discounts.json", + "input": { + "code": "WELCOME_2023", + "order": { + "createdAt": "2023-01-15" + }, + "customer": { + "joinDate": "2023-02-01", + "pastPurchases": [] + } + } + }, + { + "name": "expression-table-map", + "kind": "graph", + "file": "graphs/expression-table-map.json", + "input": { + "customer": { + "name": "John Doe", + "country": "US" + }, + "items": [ + { + "name": "item0", + "amount": 10, + "group": "accessories", + "qty": 1 + }, + { + "name": "item1", + "amount": 11, + "group": "electronics", + "qty": 2 + }, + { + "name": "item2", + "amount": 12, + "group": "electronics", + "qty": 3 + }, + { + "name": "item3", + "amount": 13, + "group": "accessories", + "qty": 4 + }, + { + "name": "item4", + "amount": 14, + "group": "electronics", + "qty": 5 + }, + { + "name": "item5", + "amount": 15, + "group": "electronics", + "qty": 1 + }, + { + "name": "item6", + "amount": 16, + "group": "accessories", + "qty": 2 + }, + { + "name": "item7", + "amount": 17, + "group": "electronics", + "qty": 3 + }, + { + "name": "item8", + "amount": 18, + "group": "electronics", + "qty": 4 + }, + { + "name": "item9", + "amount": 19, + "group": "accessories", + "qty": 5 + }, + { + "name": "item10", + "amount": 20, + "group": "electronics", + "qty": 1 + }, + { + "name": "item11", + "amount": 21, + "group": "electronics", + "qty": 2 + }, + { + "name": "item12", + "amount": 22, + "group": "accessories", + "qty": 3 + }, + { + "name": "item13", + "amount": 23, + "group": "electronics", + "qty": 4 + }, + { + "name": "item14", + "amount": 24, + "group": "electronics", + "qty": 5 + }, + { + "name": "item15", + "amount": 25, + "group": "accessories", + "qty": 1 + }, + { + "name": "item16", + "amount": 26, + "group": "electronics", + "qty": 2 + }, + { + "name": "item17", + "amount": 27, + "group": "electronics", + "qty": 3 + }, + { + "name": "item18", + "amount": 28, + "group": "accessories", + "qty": 4 + }, + { + "name": "item19", + "amount": 29, + "group": "electronics", + "qty": 5 + }, + { + "name": "item20", + "amount": 30, + "group": "electronics", + "qty": 1 + }, + { + "name": "item21", + "amount": 31, + "group": "accessories", + "qty": 2 + }, + { + "name": "item22", + "amount": 32, + "group": "electronics", + "qty": 3 + }, + { + "name": "item23", + "amount": 33, + "group": "electronics", + "qty": 4 + }, + { + "name": "item24", + "amount": 34, + "group": "accessories", + "qty": 5 + }, + { + "name": "item25", + "amount": 35, + "group": "electronics", + "qty": 1 + }, + { + "name": "item26", + "amount": 36, + "group": "electronics", + "qty": 2 + }, + { + "name": "item27", + "amount": 37, + "group": "accessories", + "qty": 3 + }, + { + "name": "item28", + "amount": 38, + "group": "electronics", + "qty": 4 + }, + { + "name": "item29", + "amount": 39, + "group": "electronics", + "qty": 5 + }, + { + "name": "item30", + "amount": 40, + "group": "accessories", + "qty": 1 + }, + { + "name": "item31", + "amount": 41, + "group": "electronics", + "qty": 2 + }, + { + "name": "item32", + "amount": 42, + "group": "electronics", + "qty": 3 + }, + { + "name": "item33", + "amount": 43, + "group": "accessories", + "qty": 4 + }, + { + "name": "item34", + "amount": 44, + "group": "electronics", + "qty": 5 + }, + { + "name": "item35", + "amount": 45, + "group": "electronics", + "qty": 1 + }, + { + "name": "item36", + "amount": 46, + "group": "accessories", + "qty": 2 + }, + { + "name": "item37", + "amount": 47, + "group": "electronics", + "qty": 3 + }, + { + "name": "item38", + "amount": 48, + "group": "electronics", + "qty": 4 + }, + { + "name": "item39", + "amount": 49, + "group": "accessories", + "qty": 5 + }, + { + "name": "item40", + "amount": 50, + "group": "electronics", + "qty": 1 + }, + { + "name": "item41", + "amount": 51, + "group": "electronics", + "qty": 2 + }, + { + "name": "item42", + "amount": 52, + "group": "accessories", + "qty": 3 + }, + { + "name": "item43", + "amount": 53, + "group": "electronics", + "qty": 4 + }, + { + "name": "item44", + "amount": 54, + "group": "electronics", + "qty": 5 + }, + { + "name": "item45", + "amount": 55, + "group": "accessories", + "qty": 1 + }, + { + "name": "item46", + "amount": 56, + "group": "electronics", + "qty": 2 + }, + { + "name": "item47", + "amount": 57, + "group": "electronics", + "qty": 3 + }, + { + "name": "item48", + "amount": 58, + "group": "accessories", + "qty": 4 + }, + { + "name": "item49", + "amount": 59, + "group": "electronics", + "qty": 5 + }, + { + "name": "item50", + "amount": 60, + "group": "electronics", + "qty": 1 + }, + { + "name": "item51", + "amount": 61, + "group": "accessories", + "qty": 2 + }, + { + "name": "item52", + "amount": 62, + "group": "electronics", + "qty": 3 + }, + { + "name": "item53", + "amount": 63, + "group": "electronics", + "qty": 4 + }, + { + "name": "item54", + "amount": 64, + "group": "accessories", + "qty": 5 + }, + { + "name": "item55", + "amount": 65, + "group": "electronics", + "qty": 1 + }, + { + "name": "item56", + "amount": 66, + "group": "electronics", + "qty": 2 + }, + { + "name": "item57", + "amount": 67, + "group": "accessories", + "qty": 3 + }, + { + "name": "item58", + "amount": 68, + "group": "electronics", + "qty": 4 + }, + { + "name": "item59", + "amount": 69, + "group": "electronics", + "qty": 5 + }, + { + "name": "item60", + "amount": 70, + "group": "accessories", + "qty": 1 + }, + { + "name": "item61", + "amount": 71, + "group": "electronics", + "qty": 2 + }, + { + "name": "item62", + "amount": 72, + "group": "electronics", + "qty": 3 + }, + { + "name": "item63", + "amount": 73, + "group": "accessories", + "qty": 4 + }, + { + "name": "item64", + "amount": 74, + "group": "electronics", + "qty": 5 + }, + { + "name": "item65", + "amount": 75, + "group": "electronics", + "qty": 1 + }, + { + "name": "item66", + "amount": 76, + "group": "accessories", + "qty": 2 + }, + { + "name": "item67", + "amount": 77, + "group": "electronics", + "qty": 3 + }, + { + "name": "item68", + "amount": 78, + "group": "electronics", + "qty": 4 + }, + { + "name": "item69", + "amount": 79, + "group": "accessories", + "qty": 5 + }, + { + "name": "item70", + "amount": 80, + "group": "electronics", + "qty": 1 + }, + { + "name": "item71", + "amount": 81, + "group": "electronics", + "qty": 2 + }, + { + "name": "item72", + "amount": 82, + "group": "accessories", + "qty": 3 + }, + { + "name": "item73", + "amount": 83, + "group": "electronics", + "qty": 4 + }, + { + "name": "item74", + "amount": 84, + "group": "electronics", + "qty": 5 + }, + { + "name": "item75", + "amount": 85, + "group": "accessories", + "qty": 1 + }, + { + "name": "item76", + "amount": 86, + "group": "electronics", + "qty": 2 + }, + { + "name": "item77", + "amount": 87, + "group": "electronics", + "qty": 3 + }, + { + "name": "item78", + "amount": 88, + "group": "accessories", + "qty": 4 + }, + { + "name": "item79", + "amount": 89, + "group": "electronics", + "qty": 5 + }, + { + "name": "item80", + "amount": 90, + "group": "electronics", + "qty": 1 + }, + { + "name": "item81", + "amount": 91, + "group": "accessories", + "qty": 2 + }, + { + "name": "item82", + "amount": 92, + "group": "electronics", + "qty": 3 + }, + { + "name": "item83", + "amount": 93, + "group": "electronics", + "qty": 4 + }, + { + "name": "item84", + "amount": 94, + "group": "accessories", + "qty": 5 + }, + { + "name": "item85", + "amount": 95, + "group": "electronics", + "qty": 1 + }, + { + "name": "item86", + "amount": 96, + "group": "electronics", + "qty": 2 + }, + { + "name": "item87", + "amount": 97, + "group": "accessories", + "qty": 3 + }, + { + "name": "item88", + "amount": 98, + "group": "electronics", + "qty": 4 + }, + { + "name": "item89", + "amount": 99, + "group": "electronics", + "qty": 5 + }, + { + "name": "item90", + "amount": 10, + "group": "accessories", + "qty": 1 + }, + { + "name": "item91", + "amount": 11, + "group": "electronics", + "qty": 2 + }, + { + "name": "item92", + "amount": 12, + "group": "electronics", + "qty": 3 + }, + { + "name": "item93", + "amount": 13, + "group": "accessories", + "qty": 4 + }, + { + "name": "item94", + "amount": 14, + "group": "electronics", + "qty": 5 + }, + { + "name": "item95", + "amount": 15, + "group": "electronics", + "qty": 1 + }, + { + "name": "item96", + "amount": 16, + "group": "accessories", + "qty": 2 + }, + { + "name": "item97", + "amount": 17, + "group": "electronics", + "qty": 3 + }, + { + "name": "item98", + "amount": 18, + "group": "electronics", + "qty": 4 + }, + { + "name": "item99", + "amount": 19, + "group": "accessories", + "qty": 5 + }, + { + "name": "item100", + "amount": 20, + "group": "electronics", + "qty": 1 + }, + { + "name": "item101", + "amount": 21, + "group": "electronics", + "qty": 2 + }, + { + "name": "item102", + "amount": 22, + "group": "accessories", + "qty": 3 + }, + { + "name": "item103", + "amount": 23, + "group": "electronics", + "qty": 4 + }, + { + "name": "item104", + "amount": 24, + "group": "electronics", + "qty": 5 + }, + { + "name": "item105", + "amount": 25, + "group": "accessories", + "qty": 1 + }, + { + "name": "item106", + "amount": 26, + "group": "electronics", + "qty": 2 + }, + { + "name": "item107", + "amount": 27, + "group": "electronics", + "qty": 3 + }, + { + "name": "item108", + "amount": 28, + "group": "accessories", + "qty": 4 + }, + { + "name": "item109", + "amount": 29, + "group": "electronics", + "qty": 5 + }, + { + "name": "item110", + "amount": 30, + "group": "electronics", + "qty": 1 + }, + { + "name": "item111", + "amount": 31, + "group": "accessories", + "qty": 2 + }, + { + "name": "item112", + "amount": 32, + "group": "electronics", + "qty": 3 + }, + { + "name": "item113", + "amount": 33, + "group": "electronics", + "qty": 4 + }, + { + "name": "item114", + "amount": 34, + "group": "accessories", + "qty": 5 + }, + { + "name": "item115", + "amount": 35, + "group": "electronics", + "qty": 1 + }, + { + "name": "item116", + "amount": 36, + "group": "electronics", + "qty": 2 + }, + { + "name": "item117", + "amount": 37, + "group": "accessories", + "qty": 3 + }, + { + "name": "item118", + "amount": 38, + "group": "electronics", + "qty": 4 + }, + { + "name": "item119", + "amount": 39, + "group": "electronics", + "qty": 5 + }, + { + "name": "item120", + "amount": 40, + "group": "accessories", + "qty": 1 + }, + { + "name": "item121", + "amount": 41, + "group": "electronics", + "qty": 2 + }, + { + "name": "item122", + "amount": 42, + "group": "electronics", + "qty": 3 + }, + { + "name": "item123", + "amount": 43, + "group": "accessories", + "qty": 4 + }, + { + "name": "item124", + "amount": 44, + "group": "electronics", + "qty": 5 + }, + { + "name": "item125", + "amount": 45, + "group": "electronics", + "qty": 1 + }, + { + "name": "item126", + "amount": 46, + "group": "accessories", + "qty": 2 + }, + { + "name": "item127", + "amount": 47, + "group": "electronics", + "qty": 3 + }, + { + "name": "item128", + "amount": 48, + "group": "electronics", + "qty": 4 + }, + { + "name": "item129", + "amount": 49, + "group": "accessories", + "qty": 5 + }, + { + "name": "item130", + "amount": 50, + "group": "electronics", + "qty": 1 + }, + { + "name": "item131", + "amount": 51, + "group": "electronics", + "qty": 2 + }, + { + "name": "item132", + "amount": 52, + "group": "accessories", + "qty": 3 + }, + { + "name": "item133", + "amount": 53, + "group": "electronics", + "qty": 4 + }, + { + "name": "item134", + "amount": 54, + "group": "electronics", + "qty": 5 + }, + { + "name": "item135", + "amount": 55, + "group": "accessories", + "qty": 1 + }, + { + "name": "item136", + "amount": 56, + "group": "electronics", + "qty": 2 + }, + { + "name": "item137", + "amount": 57, + "group": "electronics", + "qty": 3 + }, + { + "name": "item138", + "amount": 58, + "group": "accessories", + "qty": 4 + }, + { + "name": "item139", + "amount": 59, + "group": "electronics", + "qty": 5 + }, + { + "name": "item140", + "amount": 60, + "group": "electronics", + "qty": 1 + }, + { + "name": "item141", + "amount": 61, + "group": "accessories", + "qty": 2 + }, + { + "name": "item142", + "amount": 62, + "group": "electronics", + "qty": 3 + }, + { + "name": "item143", + "amount": 63, + "group": "electronics", + "qty": 4 + }, + { + "name": "item144", + "amount": 64, + "group": "accessories", + "qty": 5 + }, + { + "name": "item145", + "amount": 65, + "group": "electronics", + "qty": 1 + }, + { + "name": "item146", + "amount": 66, + "group": "electronics", + "qty": 2 + }, + { + "name": "item147", + "amount": 67, + "group": "accessories", + "qty": 3 + }, + { + "name": "item148", + "amount": 68, + "group": "electronics", + "qty": 4 + }, + { + "name": "item149", + "amount": 69, + "group": "electronics", + "qty": 5 + }, + { + "name": "item150", + "amount": 70, + "group": "accessories", + "qty": 1 + }, + { + "name": "item151", + "amount": 71, + "group": "electronics", + "qty": 2 + }, + { + "name": "item152", + "amount": 72, + "group": "electronics", + "qty": 3 + }, + { + "name": "item153", + "amount": 73, + "group": "accessories", + "qty": 4 + }, + { + "name": "item154", + "amount": 74, + "group": "electronics", + "qty": 5 + }, + { + "name": "item155", + "amount": 75, + "group": "electronics", + "qty": 1 + }, + { + "name": "item156", + "amount": 76, + "group": "accessories", + "qty": 2 + }, + { + "name": "item157", + "amount": 77, + "group": "electronics", + "qty": 3 + }, + { + "name": "item158", + "amount": 78, + "group": "electronics", + "qty": 4 + }, + { + "name": "item159", + "amount": 79, + "group": "accessories", + "qty": 5 + }, + { + "name": "item160", + "amount": 80, + "group": "electronics", + "qty": 1 + }, + { + "name": "item161", + "amount": 81, + "group": "electronics", + "qty": 2 + }, + { + "name": "item162", + "amount": 82, + "group": "accessories", + "qty": 3 + }, + { + "name": "item163", + "amount": 83, + "group": "electronics", + "qty": 4 + }, + { + "name": "item164", + "amount": 84, + "group": "electronics", + "qty": 5 + }, + { + "name": "item165", + "amount": 85, + "group": "accessories", + "qty": 1 + }, + { + "name": "item166", + "amount": 86, + "group": "electronics", + "qty": 2 + }, + { + "name": "item167", + "amount": 87, + "group": "electronics", + "qty": 3 + }, + { + "name": "item168", + "amount": 88, + "group": "accessories", + "qty": 4 + }, + { + "name": "item169", + "amount": 89, + "group": "electronics", + "qty": 5 + }, + { + "name": "item170", + "amount": 90, + "group": "electronics", + "qty": 1 + }, + { + "name": "item171", + "amount": 91, + "group": "accessories", + "qty": 2 + }, + { + "name": "item172", + "amount": 92, + "group": "electronics", + "qty": 3 + }, + { + "name": "item173", + "amount": 93, + "group": "electronics", + "qty": 4 + }, + { + "name": "item174", + "amount": 94, + "group": "accessories", + "qty": 5 + }, + { + "name": "item175", + "amount": 95, + "group": "electronics", + "qty": 1 + }, + { + "name": "item176", + "amount": 96, + "group": "electronics", + "qty": 2 + }, + { + "name": "item177", + "amount": 97, + "group": "accessories", + "qty": 3 + }, + { + "name": "item178", + "amount": 98, + "group": "electronics", + "qty": 4 + }, + { + "name": "item179", + "amount": 99, + "group": "electronics", + "qty": 5 + }, + { + "name": "item180", + "amount": 10, + "group": "accessories", + "qty": 1 + }, + { + "name": "item181", + "amount": 11, + "group": "electronics", + "qty": 2 + }, + { + "name": "item182", + "amount": 12, + "group": "electronics", + "qty": 3 + }, + { + "name": "item183", + "amount": 13, + "group": "accessories", + "qty": 4 + }, + { + "name": "item184", + "amount": 14, + "group": "electronics", + "qty": 5 + }, + { + "name": "item185", + "amount": 15, + "group": "electronics", + "qty": 1 + }, + { + "name": "item186", + "amount": 16, + "group": "accessories", + "qty": 2 + }, + { + "name": "item187", + "amount": 17, + "group": "electronics", + "qty": 3 + }, + { + "name": "item188", + "amount": 18, + "group": "electronics", + "qty": 4 + }, + { + "name": "item189", + "amount": 19, + "group": "accessories", + "qty": 5 + }, + { + "name": "item190", + "amount": 20, + "group": "electronics", + "qty": 1 + }, + { + "name": "item191", + "amount": 21, + "group": "electronics", + "qty": 2 + }, + { + "name": "item192", + "amount": 22, + "group": "accessories", + "qty": 3 + }, + { + "name": "item193", + "amount": 23, + "group": "electronics", + "qty": 4 + }, + { + "name": "item194", + "amount": 24, + "group": "electronics", + "qty": 5 + }, + { + "name": "item195", + "amount": 25, + "group": "accessories", + "qty": 1 + }, + { + "name": "item196", + "amount": 26, + "group": "electronics", + "qty": 2 + }, + { + "name": "item197", + "amount": 27, + "group": "electronics", + "qty": 3 + }, + { + "name": "item198", + "amount": 28, + "group": "accessories", + "qty": 4 + }, + { + "name": "item199", + "amount": 29, + "group": "electronics", + "qty": 5 + }, + { + "name": "item200", + "amount": 30, + "group": "electronics", + "qty": 1 + }, + { + "name": "item201", + "amount": 31, + "group": "accessories", + "qty": 2 + }, + { + "name": "item202", + "amount": 32, + "group": "electronics", + "qty": 3 + }, + { + "name": "item203", + "amount": 33, + "group": "electronics", + "qty": 4 + }, + { + "name": "item204", + "amount": 34, + "group": "accessories", + "qty": 5 + }, + { + "name": "item205", + "amount": 35, + "group": "electronics", + "qty": 1 + }, + { + "name": "item206", + "amount": 36, + "group": "electronics", + "qty": 2 + }, + { + "name": "item207", + "amount": 37, + "group": "accessories", + "qty": 3 + }, + { + "name": "item208", + "amount": 38, + "group": "electronics", + "qty": 4 + }, + { + "name": "item209", + "amount": 39, + "group": "electronics", + "qty": 5 + }, + { + "name": "item210", + "amount": 40, + "group": "accessories", + "qty": 1 + }, + { + "name": "item211", + "amount": 41, + "group": "electronics", + "qty": 2 + }, + { + "name": "item212", + "amount": 42, + "group": "electronics", + "qty": 3 + }, + { + "name": "item213", + "amount": 43, + "group": "accessories", + "qty": 4 + }, + { + "name": "item214", + "amount": 44, + "group": "electronics", + "qty": 5 + }, + { + "name": "item215", + "amount": 45, + "group": "electronics", + "qty": 1 + }, + { + "name": "item216", + "amount": 46, + "group": "accessories", + "qty": 2 + }, + { + "name": "item217", + "amount": 47, + "group": "electronics", + "qty": 3 + }, + { + "name": "item218", + "amount": 48, + "group": "electronics", + "qty": 4 + }, + { + "name": "item219", + "amount": 49, + "group": "accessories", + "qty": 5 + }, + { + "name": "item220", + "amount": 50, + "group": "electronics", + "qty": 1 + }, + { + "name": "item221", + "amount": 51, + "group": "electronics", + "qty": 2 + }, + { + "name": "item222", + "amount": 52, + "group": "accessories", + "qty": 3 + }, + { + "name": "item223", + "amount": 53, + "group": "electronics", + "qty": 4 + }, + { + "name": "item224", + "amount": 54, + "group": "electronics", + "qty": 5 + }, + { + "name": "item225", + "amount": 55, + "group": "accessories", + "qty": 1 + }, + { + "name": "item226", + "amount": 56, + "group": "electronics", + "qty": 2 + }, + { + "name": "item227", + "amount": 57, + "group": "electronics", + "qty": 3 + }, + { + "name": "item228", + "amount": 58, + "group": "accessories", + "qty": 4 + }, + { + "name": "item229", + "amount": 59, + "group": "electronics", + "qty": 5 + }, + { + "name": "item230", + "amount": 60, + "group": "electronics", + "qty": 1 + }, + { + "name": "item231", + "amount": 61, + "group": "accessories", + "qty": 2 + }, + { + "name": "item232", + "amount": 62, + "group": "electronics", + "qty": 3 + }, + { + "name": "item233", + "amount": 63, + "group": "electronics", + "qty": 4 + }, + { + "name": "item234", + "amount": 64, + "group": "accessories", + "qty": 5 + }, + { + "name": "item235", + "amount": 65, + "group": "electronics", + "qty": 1 + }, + { + "name": "item236", + "amount": 66, + "group": "electronics", + "qty": 2 + }, + { + "name": "item237", + "amount": 67, + "group": "accessories", + "qty": 3 + }, + { + "name": "item238", + "amount": 68, + "group": "electronics", + "qty": 4 + }, + { + "name": "item239", + "amount": 69, + "group": "electronics", + "qty": 5 + }, + { + "name": "item240", + "amount": 70, + "group": "accessories", + "qty": 1 + }, + { + "name": "item241", + "amount": 71, + "group": "electronics", + "qty": 2 + }, + { + "name": "item242", + "amount": 72, + "group": "electronics", + "qty": 3 + }, + { + "name": "item243", + "amount": 73, + "group": "accessories", + "qty": 4 + }, + { + "name": "item244", + "amount": 74, + "group": "electronics", + "qty": 5 + }, + { + "name": "item245", + "amount": 75, + "group": "electronics", + "qty": 1 + }, + { + "name": "item246", + "amount": 76, + "group": "accessories", + "qty": 2 + }, + { + "name": "item247", + "amount": 77, + "group": "electronics", + "qty": 3 + }, + { + "name": "item248", + "amount": 78, + "group": "electronics", + "qty": 4 + }, + { + "name": "item249", + "amount": 79, + "group": "accessories", + "qty": 5 + } + ] + } + }, + { + "name": "credit-limit-adjustment", + "kind": "graph", + "file": "graphs/credit-limit-adjustment.json", + "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 + } + } + } + }, + { + "name": "dynamic-shipping-cost-calculator", + "kind": "graph", + "file": "graphs/dynamic-shipping-cost-calculator.json", + "input": { + "shipments": [ + { + "weight": 5, + "length": 20, + "width": 15, + "height": 10, + "distance": 50, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 6, + "length": 21, + "width": 16, + "height": 11, + "distance": 51, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 7, + "length": 22, + "width": 17, + "height": 12, + "distance": 52, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 8, + "length": 23, + "width": 18, + "height": 13, + "distance": 53, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 9, + "length": 24, + "width": 19, + "height": 14, + "distance": 54, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 10, + "length": 25, + "width": 20, + "height": 15, + "distance": 55, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 11, + "length": 26, + "width": 21, + "height": 16, + "distance": 56, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 12, + "length": 27, + "width": 22, + "height": 17, + "distance": 57, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 13, + "length": 28, + "width": 23, + "height": 18, + "distance": 58, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 14, + "length": 29, + "width": 24, + "height": 19, + "distance": 59, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 15, + "length": 30, + "width": 25, + "height": 20, + "distance": 60, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 16, + "length": 31, + "width": 26, + "height": 21, + "distance": 61, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 17, + "length": 32, + "width": 27, + "height": 22, + "distance": 62, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 18, + "length": 33, + "width": 28, + "height": 23, + "distance": 63, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 19, + "length": 34, + "width": 29, + "height": 24, + "distance": 64, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 20, + "length": 35, + "width": 30, + "height": 10, + "distance": 65, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 21, + "length": 36, + "width": 31, + "height": 11, + "distance": 66, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 22, + "length": 37, + "width": 32, + "height": 12, + "distance": 67, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 23, + "length": 38, + "width": 33, + "height": 13, + "distance": 68, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 24, + "length": 39, + "width": 34, + "height": 14, + "distance": 69, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 25, + "length": 40, + "width": 15, + "height": 15, + "distance": 70, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 26, + "length": 41, + "width": 16, + "height": 16, + "distance": 71, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 27, + "length": 42, + "width": 17, + "height": 17, + "distance": 72, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 28, + "length": 43, + "width": 18, + "height": 18, + "distance": 73, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 29, + "length": 44, + "width": 19, + "height": 19, + "distance": 74, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 30, + "length": 45, + "width": 20, + "height": 20, + "distance": 75, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 31, + "length": 46, + "width": 21, + "height": 21, + "distance": 76, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 32, + "length": 47, + "width": 22, + "height": 22, + "distance": 77, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 33, + "length": 48, + "width": 23, + "height": 23, + "distance": 78, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 34, + "length": 49, + "width": 24, + "height": 24, + "distance": 79, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 35, + "length": 20, + "width": 25, + "height": 10, + "distance": 80, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 36, + "length": 21, + "width": 26, + "height": 11, + "distance": 81, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 37, + "length": 22, + "width": 27, + "height": 12, + "distance": 82, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 38, + "length": 23, + "width": 28, + "height": 13, + "distance": 83, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 39, + "length": 24, + "width": 29, + "height": 14, + "distance": 84, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 40, + "length": 25, + "width": 30, + "height": 15, + "distance": 85, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 41, + "length": 26, + "width": 31, + "height": 16, + "distance": 86, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 42, + "length": 27, + "width": 32, + "height": 17, + "distance": 87, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 43, + "length": 28, + "width": 33, + "height": 18, + "distance": 88, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 44, + "length": 29, + "width": 34, + "height": 19, + "distance": 89, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 5, + "length": 30, + "width": 15, + "height": 20, + "distance": 90, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 6, + "length": 31, + "width": 16, + "height": 21, + "distance": 91, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 7, + "length": 32, + "width": 17, + "height": 22, + "distance": 92, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 8, + "length": 33, + "width": 18, + "height": 23, + "distance": 93, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 9, + "length": 34, + "width": 19, + "height": 24, + "distance": 94, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 10, + "length": 35, + "width": 20, + "height": 10, + "distance": 95, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 11, + "length": 36, + "width": 21, + "height": 11, + "distance": 96, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 12, + "length": 37, + "width": 22, + "height": 12, + "distance": 97, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 13, + "length": 38, + "width": 23, + "height": 13, + "distance": 98, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 14, + "length": 39, + "width": 24, + "height": 14, + "distance": 99, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 15, + "length": 40, + "width": 25, + "height": 15, + "distance": 100, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 16, + "length": 41, + "width": 26, + "height": 16, + "distance": 101, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 17, + "length": 42, + "width": 27, + "height": 17, + "distance": 102, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 18, + "length": 43, + "width": 28, + "height": 18, + "distance": 103, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 19, + "length": 44, + "width": 29, + "height": 19, + "distance": 104, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 20, + "length": 45, + "width": 30, + "height": 20, + "distance": 105, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 21, + "length": 46, + "width": 31, + "height": 21, + "distance": 106, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 22, + "length": 47, + "width": 32, + "height": 22, + "distance": 107, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 23, + "length": 48, + "width": 33, + "height": 23, + "distance": 108, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 24, + "length": 49, + "width": 34, + "height": 24, + "distance": 109, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 25, + "length": 20, + "width": 15, + "height": 10, + "distance": 110, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 26, + "length": 21, + "width": 16, + "height": 11, + "distance": 111, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 27, + "length": 22, + "width": 17, + "height": 12, + "distance": 112, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 28, + "length": 23, + "width": 18, + "height": 13, + "distance": 113, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 29, + "length": 24, + "width": 19, + "height": 14, + "distance": 114, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 30, + "length": 25, + "width": 20, + "height": 15, + "distance": 115, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 31, + "length": 26, + "width": 21, + "height": 16, + "distance": 116, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 32, + "length": 27, + "width": 22, + "height": 17, + "distance": 117, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 33, + "length": 28, + "width": 23, + "height": 18, + "distance": 118, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 34, + "length": 29, + "width": 24, + "height": 19, + "distance": 119, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 35, + "length": 30, + "width": 25, + "height": 20, + "distance": 120, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 36, + "length": 31, + "width": 26, + "height": 21, + "distance": 121, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 37, + "length": 32, + "width": 27, + "height": 22, + "distance": 122, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 38, + "length": 33, + "width": 28, + "height": 23, + "distance": 123, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 39, + "length": 34, + "width": 29, + "height": 24, + "distance": 124, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 40, + "length": 35, + "width": 30, + "height": 10, + "distance": 125, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 41, + "length": 36, + "width": 31, + "height": 11, + "distance": 126, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 42, + "length": 37, + "width": 32, + "height": 12, + "distance": 127, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 43, + "length": 38, + "width": 33, + "height": 13, + "distance": 128, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 44, + "length": 39, + "width": 34, + "height": 14, + "distance": 129, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 5, + "length": 40, + "width": 15, + "height": 15, + "distance": 130, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 6, + "length": 41, + "width": 16, + "height": 16, + "distance": 131, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 7, + "length": 42, + "width": 17, + "height": 17, + "distance": 132, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 8, + "length": 43, + "width": 18, + "height": 18, + "distance": 133, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 9, + "length": 44, + "width": 19, + "height": 19, + "distance": 134, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 10, + "length": 45, + "width": 20, + "height": 20, + "distance": 135, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 11, + "length": 46, + "width": 21, + "height": 21, + "distance": 136, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 12, + "length": 47, + "width": 22, + "height": 22, + "distance": 137, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 13, + "length": 48, + "width": 23, + "height": 23, + "distance": 138, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 14, + "length": 49, + "width": 24, + "height": 24, + "distance": 139, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 15, + "length": 20, + "width": 25, + "height": 10, + "distance": 140, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 16, + "length": 21, + "width": 26, + "height": 11, + "distance": 141, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 17, + "length": 22, + "width": 27, + "height": 12, + "distance": 142, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 18, + "length": 23, + "width": 28, + "height": 13, + "distance": 143, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 19, + "length": 24, + "width": 29, + "height": 14, + "distance": 144, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 20, + "length": 25, + "width": 30, + "height": 15, + "distance": 145, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 21, + "length": 26, + "width": 31, + "height": 16, + "distance": 146, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 22, + "length": 27, + "width": 32, + "height": 17, + "distance": 147, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 23, + "length": 28, + "width": 33, + "height": 18, + "distance": 148, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 24, + "length": 29, + "width": 34, + "height": 19, + "distance": 149, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 25, + "length": 30, + "width": 15, + "height": 20, + "distance": 150, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 26, + "length": 31, + "width": 16, + "height": 21, + "distance": 151, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 27, + "length": 32, + "width": 17, + "height": 22, + "distance": 152, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 28, + "length": 33, + "width": 18, + "height": 23, + "distance": 153, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 29, + "length": 34, + "width": 19, + "height": 24, + "distance": 154, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 30, + "length": 35, + "width": 20, + "height": 10, + "distance": 155, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 31, + "length": 36, + "width": 21, + "height": 11, + "distance": 156, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 32, + "length": 37, + "width": 22, + "height": 12, + "distance": 157, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 33, + "length": 38, + "width": 23, + "height": 13, + "distance": 158, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 34, + "length": 39, + "width": 24, + "height": 14, + "distance": 159, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 35, + "length": 40, + "width": 25, + "height": 15, + "distance": 160, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 36, + "length": 41, + "width": 26, + "height": 16, + "distance": 161, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 37, + "length": 42, + "width": 27, + "height": 17, + "distance": 162, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 38, + "length": 43, + "width": 28, + "height": 18, + "distance": 163, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 39, + "length": 44, + "width": 29, + "height": 19, + "distance": 164, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 40, + "length": 45, + "width": 30, + "height": 20, + "distance": 165, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 41, + "length": 46, + "width": 31, + "height": 21, + "distance": 166, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 42, + "length": 47, + "width": 32, + "height": 22, + "distance": 167, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 43, + "length": 48, + "width": 33, + "height": 23, + "distance": 168, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 44, + "length": 49, + "width": 34, + "height": 24, + "distance": 169, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 5, + "length": 20, + "width": 15, + "height": 10, + "distance": 170, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 6, + "length": 21, + "width": 16, + "height": 11, + "distance": 171, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 7, + "length": 22, + "width": 17, + "height": 12, + "distance": 172, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 8, + "length": 23, + "width": 18, + "height": 13, + "distance": 173, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 9, + "length": 24, + "width": 19, + "height": 14, + "distance": 174, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 10, + "length": 25, + "width": 20, + "height": 15, + "distance": 175, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 11, + "length": 26, + "width": 21, + "height": 16, + "distance": 176, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 12, + "length": 27, + "width": 22, + "height": 17, + "distance": 177, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 13, + "length": 28, + "width": 23, + "height": 18, + "distance": 178, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 14, + "length": 29, + "width": 24, + "height": 19, + "distance": 179, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 15, + "length": 30, + "width": 25, + "height": 20, + "distance": 180, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 16, + "length": 31, + "width": 26, + "height": 21, + "distance": 181, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 17, + "length": 32, + "width": 27, + "height": 22, + "distance": 182, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 18, + "length": 33, + "width": 28, + "height": 23, + "distance": 183, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 19, + "length": 34, + "width": 29, + "height": 24, + "distance": 184, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 20, + "length": 35, + "width": 30, + "height": 10, + "distance": 185, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 21, + "length": 36, + "width": 31, + "height": 11, + "distance": 186, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 22, + "length": 37, + "width": 32, + "height": 12, + "distance": 187, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 23, + "length": 38, + "width": 33, + "height": 13, + "distance": 188, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 24, + "length": 39, + "width": 34, + "height": 14, + "distance": 189, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 25, + "length": 40, + "width": 15, + "height": 15, + "distance": 190, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 26, + "length": 41, + "width": 16, + "height": 16, + "distance": 191, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 27, + "length": 42, + "width": 17, + "height": 17, + "distance": 192, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 28, + "length": 43, + "width": 18, + "height": 18, + "distance": 193, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 29, + "length": 44, + "width": 19, + "height": 19, + "distance": 194, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 30, + "length": 45, + "width": 20, + "height": 20, + "distance": 195, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 31, + "length": 46, + "width": 21, + "height": 21, + "distance": 196, + "shippingType": "priority", + "customerTier": "standard" + }, + { + "weight": 32, + "length": 47, + "width": 22, + "height": 22, + "distance": 197, + "shippingType": "standard", + "customerTier": "gold" + }, + { + "weight": 33, + "length": 48, + "width": 23, + "height": 23, + "distance": 198, + "shippingType": "express", + "customerTier": "silver" + }, + { + "weight": 34, + "length": 49, + "width": 24, + "height": 24, + "distance": 199, + "shippingType": "priority", + "customerTier": "standard" + } + ] + } + }, + { + "name": "customer-eligibility-engine", + "kind": "graph", + "file": "graphs/customer-eligibility-engine.json", + "input": { + "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 + }, + "usageHistory": [ + { + "day": 0, + "dataGB": 1, + "minutes": 100, + "texts": 10 + }, + { + "day": 1, + "dataGB": 2, + "minutes": 101, + "texts": 11 + }, + { + "day": 2, + "dataGB": 3, + "minutes": 102, + "texts": 12 + }, + { + "day": 3, + "dataGB": 4, + "minutes": 103, + "texts": 13 + }, + { + "day": 4, + "dataGB": 5, + "minutes": 104, + "texts": 14 + }, + { + "day": 5, + "dataGB": 1, + "minutes": 105, + "texts": 15 + }, + { + "day": 6, + "dataGB": 2, + "minutes": 106, + "texts": 16 + }, + { + "day": 7, + "dataGB": 3, + "minutes": 107, + "texts": 17 + }, + { + "day": 8, + "dataGB": 4, + "minutes": 108, + "texts": 18 + }, + { + "day": 9, + "dataGB": 5, + "minutes": 109, + "texts": 19 + }, + { + "day": 10, + "dataGB": 1, + "minutes": 110, + "texts": 20 + }, + { + "day": 11, + "dataGB": 2, + "minutes": 111, + "texts": 21 + }, + { + "day": 12, + "dataGB": 3, + "minutes": 112, + "texts": 22 + }, + { + "day": 13, + "dataGB": 4, + "minutes": 113, + "texts": 23 + }, + { + "day": 14, + "dataGB": 5, + "minutes": 114, + "texts": 24 + }, + { + "day": 15, + "dataGB": 1, + "minutes": 115, + "texts": 25 + }, + { + "day": 16, + "dataGB": 2, + "minutes": 116, + "texts": 26 + }, + { + "day": 17, + "dataGB": 3, + "minutes": 117, + "texts": 27 + }, + { + "day": 18, + "dataGB": 4, + "minutes": 118, + "texts": 28 + }, + { + "day": 19, + "dataGB": 5, + "minutes": 119, + "texts": 29 + }, + { + "day": 20, + "dataGB": 1, + "minutes": 120, + "texts": 30 + }, + { + "day": 21, + "dataGB": 2, + "minutes": 121, + "texts": 31 + }, + { + "day": 22, + "dataGB": 3, + "minutes": 122, + "texts": 32 + }, + { + "day": 23, + "dataGB": 4, + "minutes": 123, + "texts": 33 + }, + { + "day": 24, + "dataGB": 5, + "minutes": 124, + "texts": 34 + }, + { + "day": 25, + "dataGB": 1, + "minutes": 125, + "texts": 35 + }, + { + "day": 26, + "dataGB": 2, + "minutes": 126, + "texts": 36 + }, + { + "day": 27, + "dataGB": 3, + "minutes": 127, + "texts": 37 + }, + { + "day": 28, + "dataGB": 4, + "minutes": 128, + "texts": 38 + }, + { + "day": 29, + "dataGB": 5, + "minutes": 129, + "texts": 39 + }, + { + "day": 30, + "dataGB": 1, + "minutes": 130, + "texts": 40 + }, + { + "day": 31, + "dataGB": 2, + "minutes": 131, + "texts": 41 + }, + { + "day": 32, + "dataGB": 3, + "minutes": 132, + "texts": 42 + }, + { + "day": 33, + "dataGB": 4, + "minutes": 133, + "texts": 43 + }, + { + "day": 34, + "dataGB": 5, + "minutes": 134, + "texts": 44 + }, + { + "day": 35, + "dataGB": 1, + "minutes": 135, + "texts": 45 + }, + { + "day": 36, + "dataGB": 2, + "minutes": 136, + "texts": 46 + }, + { + "day": 37, + "dataGB": 3, + "minutes": 137, + "texts": 47 + }, + { + "day": 38, + "dataGB": 4, + "minutes": 138, + "texts": 48 + }, + { + "day": 39, + "dataGB": 5, + "minutes": 139, + "texts": 49 + }, + { + "day": 40, + "dataGB": 1, + "minutes": 140, + "texts": 50 + }, + { + "day": 41, + "dataGB": 2, + "minutes": 141, + "texts": 51 + }, + { + "day": 42, + "dataGB": 3, + "minutes": 142, + "texts": 52 + }, + { + "day": 43, + "dataGB": 4, + "minutes": 143, + "texts": 53 + }, + { + "day": 44, + "dataGB": 5, + "minutes": 144, + "texts": 54 + }, + { + "day": 45, + "dataGB": 1, + "minutes": 145, + "texts": 55 + }, + { + "day": 46, + "dataGB": 2, + "minutes": 146, + "texts": 56 + }, + { + "day": 47, + "dataGB": 3, + "minutes": 147, + "texts": 57 + }, + { + "day": 48, + "dataGB": 4, + "minutes": 148, + "texts": 58 + }, + { + "day": 49, + "dataGB": 5, + "minutes": 149, + "texts": 59 + }, + { + "day": 50, + "dataGB": 1, + "minutes": 150, + "texts": 10 + }, + { + "day": 51, + "dataGB": 2, + "minutes": 151, + "texts": 11 + }, + { + "day": 52, + "dataGB": 3, + "minutes": 152, + "texts": 12 + }, + { + "day": 53, + "dataGB": 4, + "minutes": 153, + "texts": 13 + }, + { + "day": 54, + "dataGB": 5, + "minutes": 154, + "texts": 14 + }, + { + "day": 55, + "dataGB": 1, + "minutes": 155, + "texts": 15 + }, + { + "day": 56, + "dataGB": 2, + "minutes": 156, + "texts": 16 + }, + { + "day": 57, + "dataGB": 3, + "minutes": 157, + "texts": 17 + }, + { + "day": 58, + "dataGB": 4, + "minutes": 158, + "texts": 18 + }, + { + "day": 59, + "dataGB": 5, + "minutes": 159, + "texts": 19 + }, + { + "day": 60, + "dataGB": 1, + "minutes": 160, + "texts": 20 + }, + { + "day": 61, + "dataGB": 2, + "minutes": 161, + "texts": 21 + }, + { + "day": 62, + "dataGB": 3, + "minutes": 162, + "texts": 22 + }, + { + "day": 63, + "dataGB": 4, + "minutes": 163, + "texts": 23 + }, + { + "day": 64, + "dataGB": 5, + "minutes": 164, + "texts": 24 + }, + { + "day": 65, + "dataGB": 1, + "minutes": 165, + "texts": 25 + }, + { + "day": 66, + "dataGB": 2, + "minutes": 166, + "texts": 26 + }, + { + "day": 67, + "dataGB": 3, + "minutes": 167, + "texts": 27 + }, + { + "day": 68, + "dataGB": 4, + "minutes": 168, + "texts": 28 + }, + { + "day": 69, + "dataGB": 5, + "minutes": 169, + "texts": 29 + }, + { + "day": 70, + "dataGB": 1, + "minutes": 170, + "texts": 30 + }, + { + "day": 71, + "dataGB": 2, + "minutes": 171, + "texts": 31 + }, + { + "day": 72, + "dataGB": 3, + "minutes": 172, + "texts": 32 + }, + { + "day": 73, + "dataGB": 4, + "minutes": 173, + "texts": 33 + }, + { + "day": 74, + "dataGB": 5, + "minutes": 174, + "texts": 34 + }, + { + "day": 75, + "dataGB": 1, + "minutes": 175, + "texts": 35 + }, + { + "day": 76, + "dataGB": 2, + "minutes": 176, + "texts": 36 + }, + { + "day": 77, + "dataGB": 3, + "minutes": 177, + "texts": 37 + }, + { + "day": 78, + "dataGB": 4, + "minutes": 178, + "texts": 38 + }, + { + "day": 79, + "dataGB": 5, + "minutes": 179, + "texts": 39 + }, + { + "day": 80, + "dataGB": 1, + "minutes": 180, + "texts": 40 + }, + { + "day": 81, + "dataGB": 2, + "minutes": 181, + "texts": 41 + }, + { + "day": 82, + "dataGB": 3, + "minutes": 182, + "texts": 42 + }, + { + "day": 83, + "dataGB": 4, + "minutes": 183, + "texts": 43 + }, + { + "day": 84, + "dataGB": 5, + "minutes": 184, + "texts": 44 + }, + { + "day": 85, + "dataGB": 1, + "minutes": 185, + "texts": 45 + }, + { + "day": 86, + "dataGB": 2, + "minutes": 186, + "texts": 46 + }, + { + "day": 87, + "dataGB": 3, + "minutes": 187, + "texts": 47 + }, + { + "day": 88, + "dataGB": 4, + "minutes": 188, + "texts": 48 + }, + { + "day": 89, + "dataGB": 5, + "minutes": 189, + "texts": 49 + }, + { + "day": 90, + "dataGB": 1, + "minutes": 190, + "texts": 50 + }, + { + "day": 91, + "dataGB": 2, + "minutes": 191, + "texts": 51 + }, + { + "day": 92, + "dataGB": 3, + "minutes": 192, + "texts": 52 + }, + { + "day": 93, + "dataGB": 4, + "minutes": 193, + "texts": 53 + }, + { + "day": 94, + "dataGB": 5, + "minutes": 194, + "texts": 54 + }, + { + "day": 95, + "dataGB": 1, + "minutes": 195, + "texts": 55 + }, + { + "day": 96, + "dataGB": 2, + "minutes": 196, + "texts": 56 + }, + { + "day": 97, + "dataGB": 3, + "minutes": 197, + "texts": 57 + }, + { + "day": 98, + "dataGB": 4, + "minutes": 198, + "texts": 58 + }, + { + "day": 99, + "dataGB": 5, + "minutes": 199, + "texts": 59 + }, + { + "day": 100, + "dataGB": 1, + "minutes": 200, + "texts": 10 + }, + { + "day": 101, + "dataGB": 2, + "minutes": 201, + "texts": 11 + }, + { + "day": 102, + "dataGB": 3, + "minutes": 202, + "texts": 12 + }, + { + "day": 103, + "dataGB": 4, + "minutes": 203, + "texts": 13 + }, + { + "day": 104, + "dataGB": 5, + "minutes": 204, + "texts": 14 + }, + { + "day": 105, + "dataGB": 1, + "minutes": 205, + "texts": 15 + }, + { + "day": 106, + "dataGB": 2, + "minutes": 206, + "texts": 16 + }, + { + "day": 107, + "dataGB": 3, + "minutes": 207, + "texts": 17 + }, + { + "day": 108, + "dataGB": 4, + "minutes": 208, + "texts": 18 + }, + { + "day": 109, + "dataGB": 5, + "minutes": 209, + "texts": 19 + }, + { + "day": 110, + "dataGB": 1, + "minutes": 210, + "texts": 20 + }, + { + "day": 111, + "dataGB": 2, + "minutes": 211, + "texts": 21 + }, + { + "day": 112, + "dataGB": 3, + "minutes": 212, + "texts": 22 + }, + { + "day": 113, + "dataGB": 4, + "minutes": 213, + "texts": 23 + }, + { + "day": 114, + "dataGB": 5, + "minutes": 214, + "texts": 24 + }, + { + "day": 115, + "dataGB": 1, + "minutes": 215, + "texts": 25 + }, + { + "day": 116, + "dataGB": 2, + "minutes": 216, + "texts": 26 + }, + { + "day": 117, + "dataGB": 3, + "minutes": 217, + "texts": 27 + }, + { + "day": 118, + "dataGB": 4, + "minutes": 218, + "texts": 28 + }, + { + "day": 119, + "dataGB": 5, + "minutes": 219, + "texts": 29 + }, + { + "day": 120, + "dataGB": 1, + "minutes": 220, + "texts": 30 + }, + { + "day": 121, + "dataGB": 2, + "minutes": 221, + "texts": 31 + }, + { + "day": 122, + "dataGB": 3, + "minutes": 222, + "texts": 32 + }, + { + "day": 123, + "dataGB": 4, + "minutes": 223, + "texts": 33 + }, + { + "day": 124, + "dataGB": 5, + "minutes": 224, + "texts": 34 + }, + { + "day": 125, + "dataGB": 1, + "minutes": 225, + "texts": 35 + }, + { + "day": 126, + "dataGB": 2, + "minutes": 226, + "texts": 36 + }, + { + "day": 127, + "dataGB": 3, + "minutes": 227, + "texts": 37 + }, + { + "day": 128, + "dataGB": 4, + "minutes": 228, + "texts": 38 + }, + { + "day": 129, + "dataGB": 5, + "minutes": 229, + "texts": 39 + }, + { + "day": 130, + "dataGB": 1, + "minutes": 230, + "texts": 40 + }, + { + "day": 131, + "dataGB": 2, + "minutes": 231, + "texts": 41 + }, + { + "day": 132, + "dataGB": 3, + "minutes": 232, + "texts": 42 + }, + { + "day": 133, + "dataGB": 4, + "minutes": 233, + "texts": 43 + }, + { + "day": 134, + "dataGB": 5, + "minutes": 234, + "texts": 44 + }, + { + "day": 135, + "dataGB": 1, + "minutes": 235, + "texts": 45 + }, + { + "day": 136, + "dataGB": 2, + "minutes": 236, + "texts": 46 + }, + { + "day": 137, + "dataGB": 3, + "minutes": 237, + "texts": 47 + }, + { + "day": 138, + "dataGB": 4, + "minutes": 238, + "texts": 48 + }, + { + "day": 139, + "dataGB": 5, + "minutes": 239, + "texts": 49 + }, + { + "day": 140, + "dataGB": 1, + "minutes": 240, + "texts": 50 + }, + { + "day": 141, + "dataGB": 2, + "minutes": 241, + "texts": 51 + }, + { + "day": 142, + "dataGB": 3, + "minutes": 242, + "texts": 52 + }, + { + "day": 143, + "dataGB": 4, + "minutes": 243, + "texts": 53 + }, + { + "day": 144, + "dataGB": 5, + "minutes": 244, + "texts": 54 + }, + { + "day": 145, + "dataGB": 1, + "minutes": 245, + "texts": 55 + }, + { + "day": 146, + "dataGB": 2, + "minutes": 246, + "texts": 56 + }, + { + "day": 147, + "dataGB": 3, + "minutes": 247, + "texts": 57 + }, + { + "day": 148, + "dataGB": 4, + "minutes": 248, + "texts": 58 + }, + { + "day": 149, + "dataGB": 5, + "minutes": 249, + "texts": 59 + }, + { + "day": 150, + "dataGB": 1, + "minutes": 250, + "texts": 10 + }, + { + "day": 151, + "dataGB": 2, + "minutes": 251, + "texts": 11 + }, + { + "day": 152, + "dataGB": 3, + "minutes": 252, + "texts": 12 + }, + { + "day": 153, + "dataGB": 4, + "minutes": 253, + "texts": 13 + }, + { + "day": 154, + "dataGB": 5, + "minutes": 254, + "texts": 14 + }, + { + "day": 155, + "dataGB": 1, + "minutes": 255, + "texts": 15 + }, + { + "day": 156, + "dataGB": 2, + "minutes": 256, + "texts": 16 + }, + { + "day": 157, + "dataGB": 3, + "minutes": 257, + "texts": 17 + }, + { + "day": 158, + "dataGB": 4, + "minutes": 258, + "texts": 18 + }, + { + "day": 159, + "dataGB": 5, + "minutes": 259, + "texts": 19 + }, + { + "day": 160, + "dataGB": 1, + "minutes": 260, + "texts": 20 + }, + { + "day": 161, + "dataGB": 2, + "minutes": 261, + "texts": 21 + }, + { + "day": 162, + "dataGB": 3, + "minutes": 262, + "texts": 22 + }, + { + "day": 163, + "dataGB": 4, + "minutes": 263, + "texts": 23 + }, + { + "day": 164, + "dataGB": 5, + "minutes": 264, + "texts": 24 + }, + { + "day": 165, + "dataGB": 1, + "minutes": 265, + "texts": 25 + }, + { + "day": 166, + "dataGB": 2, + "minutes": 266, + "texts": 26 + }, + { + "day": 167, + "dataGB": 3, + "minutes": 267, + "texts": 27 + }, + { + "day": 168, + "dataGB": 4, + "minutes": 268, + "texts": 28 + }, + { + "day": 169, + "dataGB": 5, + "minutes": 269, + "texts": 29 + }, + { + "day": 170, + "dataGB": 1, + "minutes": 270, + "texts": 30 + }, + { + "day": 171, + "dataGB": 2, + "minutes": 271, + "texts": 31 + }, + { + "day": 172, + "dataGB": 3, + "minutes": 272, + "texts": 32 + }, + { + "day": 173, + "dataGB": 4, + "minutes": 273, + "texts": 33 + }, + { + "day": 174, + "dataGB": 5, + "minutes": 274, + "texts": 34 + }, + { + "day": 175, + "dataGB": 1, + "minutes": 275, + "texts": 35 + }, + { + "day": 176, + "dataGB": 2, + "minutes": 276, + "texts": 36 + }, + { + "day": 177, + "dataGB": 3, + "minutes": 277, + "texts": 37 + }, + { + "day": 178, + "dataGB": 4, + "minutes": 278, + "texts": 38 + }, + { + "day": 179, + "dataGB": 5, + "minutes": 279, + "texts": 39 + }, + { + "day": 180, + "dataGB": 1, + "minutes": 280, + "texts": 40 + }, + { + "day": 181, + "dataGB": 2, + "minutes": 281, + "texts": 41 + }, + { + "day": 182, + "dataGB": 3, + "minutes": 282, + "texts": 42 + }, + { + "day": 183, + "dataGB": 4, + "minutes": 283, + "texts": 43 + }, + { + "day": 184, + "dataGB": 5, + "minutes": 284, + "texts": 44 + }, + { + "day": 185, + "dataGB": 1, + "minutes": 285, + "texts": 45 + }, + { + "day": 186, + "dataGB": 2, + "minutes": 286, + "texts": 46 + }, + { + "day": 187, + "dataGB": 3, + "minutes": 287, + "texts": 47 + }, + { + "day": 188, + "dataGB": 4, + "minutes": 288, + "texts": 48 + }, + { + "day": 189, + "dataGB": 5, + "minutes": 289, + "texts": 49 + }, + { + "day": 190, + "dataGB": 1, + "minutes": 290, + "texts": 50 + }, + { + "day": 191, + "dataGB": 2, + "minutes": 291, + "texts": 51 + }, + { + "day": 192, + "dataGB": 3, + "minutes": 292, + "texts": 52 + }, + { + "day": 193, + "dataGB": 4, + "minutes": 293, + "texts": 53 + }, + { + "day": 194, + "dataGB": 5, + "minutes": 294, + "texts": 54 + }, + { + "day": 195, + "dataGB": 1, + "minutes": 295, + "texts": 55 + }, + { + "day": 196, + "dataGB": 2, + "minutes": 296, + "texts": 56 + }, + { + "day": 197, + "dataGB": 3, + "minutes": 297, + "texts": 57 + }, + { + "day": 198, + "dataGB": 4, + "minutes": 298, + "texts": 58 + }, + { + "day": 199, + "dataGB": 5, + "minutes": 299, + "texts": 59 + } + ] + } + }, + { + "name": "simple-assertion", + "kind": "policy", + "file": "policies/simple-assertion.json", + "input": { + "customer": { + "age": 30 + } + } + }, + { + "name": "expression", + "kind": "policy", + "file": "policies/expression.json", + "input": { + "customer": { + "age": 35, + "income": 60000 + } + } + }, + { + "name": "multi-assertion", + "kind": "policy", + "file": "policies/multi-assertion.json", + "input": { + "customer": { + "age": 40, + "income": 60000, + "employmentYears": 5, + "scores": [ + 0, + 13, + 26, + 39, + 52, + 65, + 78, + 91, + 4, + 17, + 30, + 43, + 56, + 69, + 82, + 95, + 8, + 21, + 34, + 47, + 60, + 73, + 86, + 99, + 12, + 25, + 38, + 51, + 64, + 77, + 90, + 3, + 16, + 29, + 42, + 55, + 68, + 81, + 94, + 7, + 20, + 33, + 46, + 59, + 72, + 85, + 98, + 11, + 24, + 37, + 50, + 63, + 76, + 89, + 2, + 15, + 28, + 41, + 54, + 67, + 80, + 93, + 6, + 19, + 32, + 45, + 58, + 71, + 84, + 97, + 10, + 23, + 36, + 49, + 62, + 75, + 88, + 1, + 14, + 27, + 40, + 53, + 66, + 79, + 92, + 5, + 18, + 31, + 44, + 57, + 70, + 83, + 96, + 9, + 22, + 35, + 48, + 61, + 74, + 87, + 0, + 13, + 26, + 39, + 52, + 65, + 78, + 91, + 4, + 17, + 30, + 43, + 56, + 69, + 82, + 95, + 8, + 21, + 34, + 47, + 60, + 73, + 86, + 99, + 12, + 25, + 38, + 51, + 64, + 77, + 90, + 3, + 16, + 29, + 42, + 55, + 68, + 81, + 94, + 7, + 20, + 33, + 46, + 59, + 72, + 85, + 98, + 11, + 24, + 37, + 50, + 63, + 76, + 89, + 2, + 15, + 28, + 41, + 54, + 67, + 80, + 93, + 6, + 19, + 32, + 45, + 58, + 71, + 84, + 97, + 10, + 23, + 36, + 49, + 62, + 75, + 88, + 1, + 14, + 27, + 40, + 53, + 66, + 79, + 92, + 5, + 18, + 31, + 44, + 57, + 70, + 83, + 96, + 9, + 22, + 35, + 48, + 61, + 74, + 87, + 0, + 13, + 26, + 39, + 52, + 65, + 78, + 91, + 4, + 17, + 30, + 43, + 56, + 69, + 82, + 95, + 8, + 21, + 34, + 47, + 60, + 73, + 86, + 99, + 12, + 25, + 38, + 51, + 64, + 77, + 90, + 3, + 16, + 29, + 42, + 55, + 68, + 81, + 94, + 7, + 20, + 33, + 46, + 59, + 72, + 85, + 98, + 11, + 24, + 37, + 50, + 63, + 76, + 89, + 2, + 15, + 28, + 41, + 54, + 67, + 80, + 93, + 6, + 19, + 32, + 45, + 58, + 71, + 84, + 97, + 10, + 23, + 36, + 49, + 62, + 75, + 88, + 1, + 14, + 27, + 40, + 53, + 66, + 79, + 92, + 5, + 18, + 31, + 44, + 57, + 70, + 83, + 96, + 9, + 22, + 35, + 48, + 61, + 74, + 87 + ] + } + } + }, + { + "name": "expression-chain", + "kind": "policy", + "file": "policies/expression-chain.json", + "input": { + "customer": { + "amounts": [ + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9, + -2, + 5, + 12, + 19, + -15, + -8, + -1, + 6, + 13, + 20, + -14, + -7, + 0, + 7, + 14, + -20, + -13, + -6, + 1, + 8, + 15, + -19, + -12, + -5, + 2, + 9, + 16, + -18, + -11, + -4, + 3, + 10, + 17, + -17, + -10, + -3, + 4, + 11, + 18, + -16, + -9 + ], + "label": "batch" + } + } + }, + { + "name": "match", + "kind": "policy", + "file": "policies/match.json", + "input": { + "customer": { + "score": 85 + } + } + } +] diff --git a/benchmark/node/bench.mjs b/benchmark/node/bench.mjs new file mode 100644 index 00000000..32ffe39d --- /dev/null +++ b/benchmark/node/bench.mjs @@ -0,0 +1,43 @@ +import { readFile } from 'node:fs/promises'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { hrtime, argv, env } from 'node:process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createRequire } from 'node:module'; + +const require = createRequire(import.meta.url); +const { ZenEngine } = require('../../bindings/nodejs/index.js'); + +const dir = path.dirname(fileURLToPath(import.meta.url)); +const root = path.join(dir, '..'); +const fixtures = path.join(root, 'fixtures'); +const manifest = JSON.parse(readFileSync(path.join(root, 'manifest.json'), 'utf8')); +const iters = Number(env.BENCH_ITERS || 2000); +const outPath = argv[2]; + +const loader = (key) => readFile(path.join(fixtures, key)); +const engine = new ZenEngine({ loader }); + +const results = []; +for (const e of manifest) { + for (const trace of [false, true]) { + const opts = { trace }; + await engine.evaluate(e.file, e.input, opts); + const start = hrtime.bigint(); + for (let i = 0; i < iters; i++) { + await engine.evaluate(e.file, e.input, opts); + } + const per = Number(hrtime.bigint() - start) / iters; + results.push({ name: `${e.name} (${e.kind})${trace ? ' +trace' : ''}`, unit: 'ns/op', value: per }); + } +} + +engine.dispose?.(); + +if (outPath) { + writeFileSync(outPath, JSON.stringify(results, null, 2)); +} else { + for (const r of results) { + console.log(`${r.name.padEnd(44)} ${r.value.toFixed(0).padStart(12)} ns/op`); + } +} diff --git a/benchmark/python/bench.py b/benchmark/python/bench.py new file mode 100644 index 00000000..b25f303e --- /dev/null +++ b/benchmark/python/bench.py @@ -0,0 +1,39 @@ +import json +import os +import sys +import time + +import zen + +root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +fixtures = os.path.join(root, "fixtures") +manifest = json.load(open(os.path.join(root, "manifest.json"))) +iters = int(os.environ.get("BENCH_ITERS", "2000")) +out_path = sys.argv[1] if len(sys.argv) > 1 else None + + +def loader(key): + with open(os.path.join(fixtures, key)) as f: + return f.read() + + +engine = zen.ZenEngine({"loader": loader}) + +results = [] +for e in manifest: + for trace in (False, True): + opts = {"trace": trace} + engine.evaluate(e["file"], e["input"], opts) + start = time.perf_counter_ns() + for _ in range(iters): + engine.evaluate(e["file"], e["input"], opts) + per = (time.perf_counter_ns() - start) / iters + suffix = " +trace" if trace else "" + results.append({"name": f'{e["name"]} ({e["kind"]}){suffix}', "unit": "ns/op", "value": per}) + +if out_path: + with open(out_path, "w") as f: + f.write(json.dumps(results, indent=2)) +else: + for r in results: + print(f'{r["name"]:<44} {r["value"]:>12.0f} ns/op') diff --git a/benchmark/rust/Cargo.toml b/benchmark/rust/Cargo.toml new file mode 100644 index 00000000..25ca083f --- /dev/null +++ b/benchmark/rust/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "zen-benchmark" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +zen-engine = { path = "../../core/engine" } +zen-expression = { path = "../../core/expression" } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } diff --git a/benchmark/rust/src/main.rs b/benchmark/rust/src/main.rs new file mode 100644 index 00000000..207d9af4 --- /dev/null +++ b/benchmark/rust/src/main.rs @@ -0,0 +1,99 @@ +use std::path::Path; +use std::sync::Arc; +use std::time::Instant; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use zen_engine::loader::{FilesystemLoader, FilesystemLoaderOptions}; +use zen_engine::{DecisionEngine, EvaluationOptions}; +use zen_expression::Variable; + +#[derive(Deserialize)] +struct Entry { + name: String, + kind: String, + file: String, + input: Value, +} + +#[derive(Serialize)] +struct BenchResult { + name: String, + unit: String, + value: f64, +} + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + let mut args = std::env::args().skip(1); + let manifest_path = args + .next() + .unwrap_or_else(|| "../manifest.json".to_string()); + let out_path = args.next(); + let iters: u32 = std::env::var("BENCH_ITERS") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(2000); + + let manifest_path = Path::new(&manifest_path); + let base = manifest_path + .parent() + .unwrap_or_else(|| Path::new(".")) + .join("fixtures"); + let manifest: Vec = + serde_json::from_str(&std::fs::read_to_string(manifest_path).expect("read manifest")) + .expect("parse manifest"); + + let engine = DecisionEngine::default().with_loader(Arc::new(FilesystemLoader::new( + FilesystemLoaderOptions { + root: base.to_string_lossy().to_string(), + }, + ))); + + let mut results = Vec::new(); + for e in &manifest { + let input: Variable = e.input.clone().into(); + for trace in [false, true] { + let opts = || EvaluationOptions { + trace, + max_depth: 10, + }; + engine + .evaluate_with_opts(e.file.as_str(), input.clone(), opts()) + .await + .unwrap_or_else(|err| panic!("warmup {} failed: {err:?}", e.name)); + + let start = Instant::now(); + for _ in 0..iters { + engine + .evaluate_with_opts(e.file.as_str(), input.clone(), opts()) + .await + .unwrap(); + } + let per = start.elapsed().as_nanos() as f64 / f64::from(iters); + + results.push(BenchResult { + name: format!( + "{} ({}){}", + e.name, + e.kind, + if trace { " +trace" } else { "" } + ), + unit: "ns/op".to_string(), + value: per, + }); + } + } + + match out_path { + Some(p) => { + let json = serde_json::to_string_pretty(&results).expect("serialize results"); + std::fs::write(p, json).expect("write output"); + } + None => { + for r in &results { + println!("{:<44} {:>12.0} ns/op", r.name, r.value); + } + } + } +} diff --git a/bindings/nodejs/index.js b/bindings/nodejs/index.js index cde6209b..e22266d9 100644 --- a/bindings/nodejs/index.js +++ b/bindings/nodejs/index.js @@ -77,8 +77,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-android-arm64') const bindingPackageVersion = require('@gorules/zen-engine-android-arm64/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -93,8 +93,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-android-arm-eabi') const bindingPackageVersion = require('@gorules/zen-engine-android-arm-eabi/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -114,8 +114,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-win32-x64-gnu') const bindingPackageVersion = require('@gorules/zen-engine-win32-x64-gnu/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -130,8 +130,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-win32-x64-msvc') const bindingPackageVersion = require('@gorules/zen-engine-win32-x64-msvc/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -147,8 +147,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-win32-ia32-msvc') const bindingPackageVersion = require('@gorules/zen-engine-win32-ia32-msvc/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -163,8 +163,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-win32-arm64-msvc') const bindingPackageVersion = require('@gorules/zen-engine-win32-arm64-msvc/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -182,8 +182,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-darwin-universal') const bindingPackageVersion = require('@gorules/zen-engine-darwin-universal/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -198,8 +198,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-darwin-x64') const bindingPackageVersion = require('@gorules/zen-engine-darwin-x64/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -214,8 +214,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-darwin-arm64') const bindingPackageVersion = require('@gorules/zen-engine-darwin-arm64/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -234,8 +234,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-freebsd-x64') const bindingPackageVersion = require('@gorules/zen-engine-freebsd-x64/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -250,8 +250,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-freebsd-arm64') const bindingPackageVersion = require('@gorules/zen-engine-freebsd-arm64/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -271,8 +271,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-x64-musl') const bindingPackageVersion = require('@gorules/zen-engine-linux-x64-musl/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -287,8 +287,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-x64-gnu') const bindingPackageVersion = require('@gorules/zen-engine-linux-x64-gnu/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -305,8 +305,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-arm64-musl') const bindingPackageVersion = require('@gorules/zen-engine-linux-arm64-musl/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -321,8 +321,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-arm64-gnu') const bindingPackageVersion = require('@gorules/zen-engine-linux-arm64-gnu/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -339,8 +339,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-arm-musleabihf') const bindingPackageVersion = require('@gorules/zen-engine-linux-arm-musleabihf/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -355,8 +355,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-arm-gnueabihf') const bindingPackageVersion = require('@gorules/zen-engine-linux-arm-gnueabihf/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -373,8 +373,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-loong64-musl') const bindingPackageVersion = require('@gorules/zen-engine-linux-loong64-musl/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -389,8 +389,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-loong64-gnu') const bindingPackageVersion = require('@gorules/zen-engine-linux-loong64-gnu/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -407,8 +407,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-riscv64-musl') const bindingPackageVersion = require('@gorules/zen-engine-linux-riscv64-musl/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -423,8 +423,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-riscv64-gnu') const bindingPackageVersion = require('@gorules/zen-engine-linux-riscv64-gnu/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -440,8 +440,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-ppc64-gnu') const bindingPackageVersion = require('@gorules/zen-engine-linux-ppc64-gnu/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -456,8 +456,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-linux-s390x-gnu') const bindingPackageVersion = require('@gorules/zen-engine-linux-s390x-gnu/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -476,8 +476,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-openharmony-arm64') const bindingPackageVersion = require('@gorules/zen-engine-openharmony-arm64/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -492,8 +492,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-openharmony-x64') const bindingPackageVersion = require('@gorules/zen-engine-openharmony-x64/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -508,8 +508,8 @@ function requireNative() { try { const binding = require('@gorules/zen-engine-openharmony-arm') const bindingPackageVersion = require('@gorules/zen-engine-openharmony-arm/package.json').version - if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { diff --git a/release-please-config.json b/release-please-config.json index 0b4b1c9e..d5a748f4 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -4,6 +4,7 @@ "include-component-in-tag": true, "tag-separator": "-", "pull-request-title-pattern": "chore(release): publish", + "group-pull-request-title-pattern": "chore(release): publish", "release-as": "1.0.0-beta.0", "prerelease": true, "prerelease-type": "beta",