@criterionx/core 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +41 -83
  2. package/package.json +14 -20
package/README.md CHANGED
@@ -1,30 +1,6 @@
1
- <p align="center">
2
- <img src="criterion.jpg" alt="Criterion" width="100%" />
3
- </p>
1
+ # @criterionx/core
4
2
 
5
- <p align="center">
6
- <strong>A universal, deterministic, and explainable decision engine for business-critical systems.</strong>
7
- </p>
8
-
9
- <p align="center">
10
- <a href="https://www.npmjs.com/package/@criterionx/core"><img src="https://img.shields.io/npm/v/@criterionx/core.svg" alt="npm version"></a>
11
- <a href="https://github.com/tomymaritano/criterionx/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@criterionx/core.svg" alt="license"></a>
12
- <a href="https://tomymaritano.github.io/criterionx/"><img src="https://img.shields.io/badge/docs-vitepress-brightgreen.svg" alt="docs"></a>
13
- </p>
14
-
15
- ---
16
-
17
- ## What is Criterion?
18
-
19
- Criterion helps you encode business decisions as **pure, testable functions** with built-in validation and explainability.
20
-
21
- Instead of scattering `if/else` statements across your codebase, you define decisions declaratively:
22
-
23
- - **"Should this transaction be flagged as high-risk?"**
24
- - **"Is this user eligible for a premium tier?"**
25
- - **"What discount applies to this order?"**
26
-
27
- Every decision returns not just a result, but a complete explanation of *why* that result was reached — perfect for audits, debugging, and compliance.
3
+ Universal decision engine for business-critical decisions.
28
4
 
29
5
  ## Installation
30
6
 
@@ -42,14 +18,15 @@ const riskDecision = defineDecision({
42
18
  id: "transaction-risk",
43
19
  version: "1.0.0",
44
20
  inputSchema: z.object({ amount: z.number() }),
45
- outputSchema: z.object({ risk: z.enum(["HIGH", "MEDIUM", "LOW"]) }),
21
+ outputSchema: z.object({ risk: z.enum(["HIGH", "LOW"]) }),
46
22
  profileSchema: z.object({ threshold: z.number() }),
47
23
  rules: [
48
24
  {
49
25
  id: "high-risk",
50
26
  when: (input, profile) => input.amount > profile.threshold,
51
27
  emit: () => ({ risk: "HIGH" }),
52
- explain: (input, profile) => `Amount ${input.amount} > ${profile.threshold}`,
28
+ explain: (input, profile) =>
29
+ `Amount ${input.amount} exceeds threshold ${profile.threshold}`,
53
30
  },
54
31
  {
55
32
  id: "low-risk",
@@ -67,77 +44,58 @@ const result = engine.run(
67
44
  { profile: { threshold: 10000 } }
68
45
  );
69
46
 
70
- console.log(result.data); // { risk: "HIGH" }
71
- console.log(engine.explain(result));
72
- // Decision: transaction-risk v1.0.0
73
- // Status: OK
74
- // Matched: high-risk
75
- // Reason: Amount 15000 > 10000
47
+ console.log(result.data); // { risk: "HIGH" }
76
48
  ```
77
49
 
78
- ## Features
79
-
80
- - **Pure & Deterministic** — Same input always produces the same output
81
- - **Fully Explainable** — Every decision includes a complete audit trail
82
- - **Contract-First** — Zod schemas validate inputs, outputs, and profiles
83
- - **Profile-Driven** — Parameterize decisions by region, tier, or environment
84
- - **Zero Side Effects** — No I/O, no database, no external calls
85
- - **Testable by Design** — Pure functions are trivial to test
86
-
87
- ## Documentation
50
+ ---
88
51
 
89
- Full documentation available at **[tomymaritano.github.io/criterion](https://tomymaritano.github.io/criterionx/)**
52
+ ## Architectural Invariants
90
53
 
91
- - [Getting Started](https://tomymaritano.github.io/criterionx/guide/getting-started)
92
- - [Core Concepts](https://tomymaritano.github.io/criterionx/guide/core-concepts)
93
- - [API Reference](https://tomymaritano.github.io/criterionx/api/engine)
94
- - [Examples](https://tomymaritano.github.io/criterionx/examples/currency-risk)
54
+ > **This package is HTTP-agnostic. It must never depend on server concerns.**
95
55
 
96
- ## Core Concepts
56
+ ### Non-Negotiable Principles
97
57
 
98
- ### Decisions
58
+ 1. **Pure and Deterministic**
59
+ - Same input + same profile = same output, always
60
+ - No hidden state, no side effects
99
61
 
100
- A decision is a unit of business logic with:
101
- - **Input schema** What data is required
102
- - **Output schema** What the decision returns
103
- - **Profile schema** What can be parameterized
104
- - **Rules** The evaluation logic
62
+ 2. **No I/O in Rules**
63
+ - Rules cannot fetch data
64
+ - Rules cannot make network calls
65
+ - Rules cannot read from filesystem
66
+ - All data must be passed in as context
105
67
 
106
- ### Rules
68
+ 3. **Explicit Dependencies**
69
+ - No auto-discovery
70
+ - No magic imports
71
+ - Decisions are explicitly passed to consumers
107
72
 
108
- Rules are evaluated in order. First match wins:
73
+ 4. **Validation at Boundaries**
74
+ - Input validated via Zod schema
75
+ - Output validated via Zod schema
76
+ - Profile validated via Zod schema
109
77
 
110
- ```typescript
111
- rules: [
112
- { id: "rule-1", when: (i) => i.x > 100, emit: ..., explain: ... },
113
- { id: "rule-2", when: (i) => i.x > 50, emit: ..., explain: ... },
114
- { id: "default", when: () => true, emit: ..., explain: ... },
115
- ]
116
- ```
78
+ 5. **Explainability**
79
+ - Every rule has an `explain` function
80
+ - Every result includes full audit trace
117
81
 
118
- ### Profiles
82
+ ### What This Package Does NOT Do
119
83
 
120
- Profiles parameterize decisions without changing logic:
84
+ - HTTP/REST handling (use `@criterionx/server`)
85
+ - Database operations
86
+ - File system access
87
+ - Network requests
88
+ - Caching
89
+ - Authentication/Authorization
121
90
 
122
- ```typescript
123
- // Same decision, different thresholds
124
- engine.run(decision, input, { profile: usProfile });
125
- engine.run(decision, input, { profile: euProfile });
126
- ```
91
+ This is intentional. The core is a knife, not a Swiss Army knife.
127
92
 
128
- ## What Criterion Is NOT
93
+ ---
129
94
 
130
- - A workflow/BPMN engine
131
- - A machine learning framework
132
- - A data pipeline
133
- - A plugin marketplace
95
+ ## Documentation
134
96
 
135
- Criterion is a **micro engine**: small core, strict boundaries.
97
+ Full documentation: [https://tomymaritano.github.io/criterionx/](https://tomymaritano.github.io/criterionx/)
136
98
 
137
99
  ## License
138
100
 
139
- [MIT](LICENSE)
140
-
141
- ## Author
142
-
143
- **Tomas Maritano** — [@tomymaritano](https://github.com/tomymaritano)
101
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@criterionx/core",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Universal decision engine for business-critical decisions",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,18 +16,6 @@
16
16
  "LICENSE",
17
17
  "README.md"
18
18
  ],
19
- "scripts": {
20
- "build": "tsup src/index.ts --format esm --dts --clean",
21
- "test": "vitest run",
22
- "test:watch": "vitest",
23
- "test:coverage": "vitest run --coverage",
24
- "typecheck": "tsc --noEmit",
25
- "benchmark": "tsx benchmarks/run.ts",
26
- "prepublishOnly": "npm run build",
27
- "docs:dev": "vitepress dev docs",
28
- "docs:build": "vitepress build docs",
29
- "docs:preview": "vitepress preview docs"
30
- },
31
19
  "keywords": [
32
20
  "decision-engine",
33
21
  "rules-engine",
@@ -46,25 +34,31 @@
46
34
  "license": "MIT",
47
35
  "repository": {
48
36
  "type": "git",
49
- "url": "https://github.com/tomymaritano/criterionx.git"
37
+ "url": "https://github.com/tomymaritano/criterionx.git",
38
+ "directory": "packages/core"
50
39
  },
51
40
  "bugs": {
52
41
  "url": "https://github.com/tomymaritano/criterionx/issues"
53
42
  },
54
43
  "homepage": "https://github.com/tomymaritano/criterionx#readme",
44
+ "peerDependencies": {
45
+ "zod": "^3.22.0"
46
+ },
55
47
  "devDependencies": {
56
48
  "@vitest/coverage-v8": "^2.0.0",
57
49
  "tsup": "^8.0.0",
58
- "tsx": "^4.7.0",
59
50
  "typescript": "^5.3.0",
60
- "vitepress": "^1.6.4",
61
51
  "vitest": "^2.0.0",
62
52
  "zod": "^3.22.0"
63
53
  },
64
- "peerDependencies": {
65
- "zod": "^3.22.0"
66
- },
67
54
  "engines": {
68
55
  "node": ">=18"
56
+ },
57
+ "scripts": {
58
+ "build": "tsup src/index.ts --format esm --dts --clean",
59
+ "test": "vitest run",
60
+ "test:watch": "vitest",
61
+ "test:coverage": "vitest run --coverage",
62
+ "typecheck": "tsc --noEmit"
69
63
  }
70
- }
64
+ }