@lexq/cli 0.1.40 → 0.1.41
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.
- package/AGENTS.md +34 -32
- package/CONTEXT.md +41 -47
- package/README.md +8 -6
- package/dist/index.js +119 -385
- package/dist/mcp/register.js +86 -166
- package/package.json +1 -1
- package/skills/lexq-execution/SKILL.md +120 -65
- package/skills/lexq-groups/SKILL.md +78 -38
- package/skills/lexq-recipes/SKILL.md +97 -193
- package/skills/lexq-rules/SKILL.md +105 -35
- package/skills/lexq-shared/SKILL.md +48 -28
- package/skills/lexq-simulation/SKILL.md +33 -33
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
A **Policy Rule** is a condition → actions pair within a version. Rules are evaluated in priority
|
|
8
|
-
|
|
7
|
+
A **Policy Rule** is a condition → actions pair within a version. Rules are evaluated in priority
|
|
8
|
+
order — **lower number wins**, and priorities are 1-based (1 is highest). When a rule's condition
|
|
9
|
+
matches the input facts, its actions fire.
|
|
10
|
+
|
|
11
|
+
`priority` is assigned by the server, not by you. New rules are appended last. Use
|
|
12
|
+
`lexq rules reorder` to change the order.
|
|
9
13
|
|
|
10
14
|
## Rule Structure
|
|
11
15
|
|
|
12
16
|
```json
|
|
13
17
|
{
|
|
14
18
|
"name": "VIP 10% Discount",
|
|
15
|
-
"priority": 0,
|
|
16
19
|
"condition": {
|
|
17
20
|
...
|
|
18
21
|
},
|
|
@@ -21,7 +24,7 @@ When a rule's condition matches the input facts, its actions fire.
|
|
|
21
24
|
],
|
|
22
25
|
"mutexGroup": null,
|
|
23
26
|
"mutexMode": "NONE",
|
|
24
|
-
"mutexStrategy": "
|
|
27
|
+
"mutexStrategy": "HIGHEST_PRIORITY",
|
|
25
28
|
"mutexLimit": null,
|
|
26
29
|
"isEnabled": true
|
|
27
30
|
}
|
|
@@ -175,21 +178,71 @@ Do **not** use `CONTAINS` on a list fact — that idiom works in some rule engin
|
|
|
175
178
|
|
|
176
179
|
Each rule can have multiple actions. Actions fire sequentially.
|
|
177
180
|
|
|
178
|
-
| Type
|
|
179
|
-
|
|
180
|
-
| `MUTATE_FACT`
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
181
|
+
| Type | Description | Key Parameters |
|
|
182
|
+
|---------------|--------------------------------------------|----------------------------------------------------------------------|
|
|
183
|
+
| `MUTATE_FACT` | Arithmetic change to a numeric fact | `targetVar`, `operator`, `method`, `operand`, `refVar?`, `rounding?` |
|
|
184
|
+
| `SET_FACT` | Assign a literal value — creates if absent | `targetVar`, `value` |
|
|
185
|
+
| `BLOCK` | Record a rejection decision | `reason` |
|
|
186
|
+
|
|
187
|
+
### `MUTATE_FACT` parameters
|
|
188
|
+
|
|
189
|
+
| Parameter | Required | Meaning |
|
|
190
|
+
|-------------|----------|-------------------------------------------------------------------------------|
|
|
191
|
+
| `targetVar` | always | The fact this action **reads and writes**. Must already exist as a number. |
|
|
192
|
+
| `operator` | always | `ASSIGN` \| `ADD` \| `SUB` \| `MUL` \| `DIV` |
|
|
193
|
+
| `method` | always | `PERCENTAGE` \| `AMOUNT` — dictates the unit of `operand` |
|
|
194
|
+
| `operand` | always | The arithmetic operand. Percent when PERCENTAGE, absolute amount when AMOUNT. |
|
|
195
|
+
| `refVar` | optional | Base for percentage calculation. Omit to use `targetVar` itself. |
|
|
196
|
+
| `rounding` | optional | `{ scale: 0..16, mode?: HALF_UP \| ... }`. Omit for lossless full precision. |
|
|
197
|
+
|
|
198
|
+
**operator × method matrix**
|
|
199
|
+
|
|
200
|
+
| operator | `AMOUNT` | `PERCENTAGE` |
|
|
201
|
+
|----------|------------------------|-------------------------------------|
|
|
202
|
+
| `ASSIGN` | `targetVar = operand` | `targetVar = refVar × operand/100` |
|
|
203
|
+
| `ADD` | `targetVar += operand` | `targetVar += refVar × operand/100` |
|
|
204
|
+
| `SUB` | `targetVar -= operand` | `targetVar -= refVar × operand/100` |
|
|
205
|
+
| `MUL` | `targetVar *= operand` | `targetVar *= (operand/100 + 1)` |
|
|
206
|
+
| `DIV` | `targetVar /= operand` | **invalid** |
|
|
207
|
+
|
|
208
|
+
`DIV` + `PERCENTAGE` is rejected — use `MUL` with the inverse. `DIV` + `AMOUNT` requires
|
|
209
|
+
`operand !== 0`.
|
|
210
|
+
|
|
211
|
+
**`refVar` is only meaningful in `PERCENTAGE` × {`ASSIGN`, `ADD`, `SUB`}.** Specifying it in any
|
|
212
|
+
other cell is an error, not a silent no-op. `AMOUNT` has no base concept, and `MUL` × `PERCENTAGE`
|
|
213
|
+
is a multiplier shorthand that does not read a base.
|
|
214
|
+
|
|
215
|
+
Use `refVar` when the base differs from the target:
|
|
216
|
+
|
|
217
|
+
```json
|
|
218
|
+
{
|
|
219
|
+
"type": "MUTATE_FACT",
|
|
220
|
+
"parameters": {
|
|
221
|
+
"targetVar": "loyalty_point",
|
|
222
|
+
"refVar": "order_total",
|
|
223
|
+
"operator": "ADD",
|
|
224
|
+
"method": "PERCENTAGE",
|
|
225
|
+
"operand": 5
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`loyalty_point += order_total × 5%` — two different facts. Omitting `refVar` would compute
|
|
231
|
+
`loyalty_point += loyalty_point × 5%` instead.
|
|
232
|
+
|
|
233
|
+
**Ranges are not constrained.** Negative operands and percentages above 100 are valid — refunds
|
|
234
|
+
(`-5`), surcharges (`150`), risk scores, and game points all need them.
|
|
235
|
+
|
|
236
|
+
### `SET_FACT` vs `MUTATE_FACT`
|
|
237
|
+
|
|
238
|
+
`SET_FACT` creates the fact if it does not exist. `MUTATE_FACT` requires the target to already be
|
|
239
|
+
present as a number and throws otherwise. "Make something that wasn't there" is `SET_FACT`'s job.
|
|
240
|
+
|
|
241
|
+
### `BLOCK` does not halt execution
|
|
242
|
+
|
|
243
|
+
`BLOCK` records a rejection decision by writing the `is_blocked` fact. Subsequent actions in the
|
|
244
|
+
same rule and subsequent winning rules still run. Enforcement is the caller's responsibility —
|
|
245
|
+
read `is_blocked` from the response.
|
|
193
246
|
|
|
194
247
|
### Action Example: 10% Discount via MUTATE_FACT
|
|
195
248
|
|
|
@@ -200,10 +253,10 @@ Reduces `payment_amount` by 10%. `__delta` is auto-generated in `generatedVariab
|
|
|
200
253
|
{
|
|
201
254
|
"type": "MUTATE_FACT",
|
|
202
255
|
"parameters": {
|
|
203
|
-
"
|
|
256
|
+
"targetVar": "payment_amount",
|
|
204
257
|
"method": "PERCENTAGE",
|
|
205
258
|
"operator": "SUB",
|
|
206
|
-
"
|
|
259
|
+
"operand": 10,
|
|
207
260
|
"rounding": {
|
|
208
261
|
"mode": "HALF_UP",
|
|
209
262
|
"scale": 0
|
|
@@ -218,8 +271,7 @@ Reduces `payment_amount` by 10%. `__delta` is auto-generated in `generatedVariab
|
|
|
218
271
|
{
|
|
219
272
|
"type": "BLOCK",
|
|
220
273
|
"parameters": {
|
|
221
|
-
"reason": "Suspected fraud"
|
|
222
|
-
"code": "FRAUD_DETECTED"
|
|
274
|
+
"reason": "Suspected fraud"
|
|
223
275
|
}
|
|
224
276
|
}
|
|
225
277
|
```
|
|
@@ -245,7 +297,6 @@ lexq rules get --group-id <gid> --version-id <vid> --id <ruleId>
|
|
|
245
297
|
```bash
|
|
246
298
|
lexq rules create --group-id <gid> --version-id <vid> --json '{
|
|
247
299
|
"name": "VIP 10% Discount",
|
|
248
|
-
"priority": 0,
|
|
249
300
|
"condition": {
|
|
250
301
|
"type": "GROUP",
|
|
251
302
|
"operator": "AND",
|
|
@@ -258,10 +309,10 @@ lexq rules create --group-id <gid> --version-id <vid> --json '{
|
|
|
258
309
|
{
|
|
259
310
|
"type": "MUTATE_FACT",
|
|
260
311
|
"parameters": {
|
|
261
|
-
"
|
|
312
|
+
"targetVar": "payment_amount",
|
|
262
313
|
"method": "PERCENTAGE",
|
|
263
314
|
"operator": "SUB",
|
|
264
|
-
"
|
|
315
|
+
"operand": 10,
|
|
265
316
|
"rounding": { "mode": "HALF_UP", "scale": 0 }
|
|
266
317
|
}
|
|
267
318
|
}
|
|
@@ -279,10 +330,10 @@ lexq rules update --group-id <gid> --version-id <vid> --id <ruleId> --json '{
|
|
|
279
330
|
{
|
|
280
331
|
"type": "MUTATE_FACT",
|
|
281
332
|
"parameters": {
|
|
282
|
-
"
|
|
333
|
+
"targetVar": "payment_amount",
|
|
283
334
|
"method": "PERCENTAGE",
|
|
284
335
|
"operator": "SUB",
|
|
285
|
-
"
|
|
336
|
+
"operand": 15,
|
|
286
337
|
"rounding": { "mode": "HALF_UP", "scale": 0 }
|
|
287
338
|
}
|
|
288
339
|
}
|
|
@@ -299,7 +350,8 @@ lexq rules delete --group-id <gid> --version-id <vid> --id <ruleId> --force
|
|
|
299
350
|
|
|
300
351
|
### Reorder Rules
|
|
301
352
|
|
|
302
|
-
Pass rule IDs in desired priority
|
|
353
|
+
Pass rule IDs in desired order. The server assigns priority 1, 2, 3, … — the first ID becomes
|
|
354
|
+
priority 1 (highest):
|
|
303
355
|
|
|
304
356
|
```bash
|
|
305
357
|
lexq rules reorder --group-id <gid> --version-id <vid> \
|
|
@@ -319,26 +371,44 @@ lexq rules toggle --group-id <gid> --version-id <vid> --id <ruleId> --enabled fa
|
|
|
319
371
|
|
|
320
372
|
Within a single version, rules can belong to a `mutexGroup` to limit how many fire.
|
|
321
373
|
|
|
322
|
-
| mutexMode | Behavior
|
|
323
|
-
|
|
324
|
-
| `NONE` | All matching rules fire (default)
|
|
325
|
-
| `EXCLUSIVE` | Only one rule per mutex group fires
|
|
326
|
-
| `MAX_N` | Up to `mutexLimit` rules
|
|
374
|
+
| mutexMode | Behavior |
|
|
375
|
+
|-------------|---------------------------------------------------------------|
|
|
376
|
+
| `NONE` | All matching rules fire (default) |
|
|
377
|
+
| `EXCLUSIVE` | Only one rule per mutex group fires |
|
|
378
|
+
| `MAX_N` | Up to `mutexLimit` rules fire. Omit it and the server sets 2. |
|
|
327
379
|
|
|
328
380
|
```bash
|
|
329
381
|
lexq rules create --group-id <gid> --version-id <vid> --json '{
|
|
330
382
|
"name": "Discount A",
|
|
331
|
-
"priority": 0,
|
|
332
383
|
"mutexGroup": "discounts",
|
|
333
384
|
"mutexMode": "EXCLUSIVE",
|
|
334
385
|
"mutexStrategy": "HIGHEST_PRIORITY",
|
|
335
386
|
"condition": { ... },
|
|
336
387
|
"actions": [ ... ]
|
|
337
388
|
}'
|
|
389
|
+
|
|
390
|
+
# Top two of the group fire
|
|
391
|
+
lexq rules create --group-id <gid> --version-id <vid> --json '{
|
|
392
|
+
"name": "Stackable Promo A",
|
|
393
|
+
"mutexGroup": "promos",
|
|
394
|
+
"mutexMode": "MAX_N",
|
|
395
|
+
"mutexLimit": 2,
|
|
396
|
+
"mutexStrategy": "HIGHEST_PRIORITY",
|
|
397
|
+
"condition": { ... },
|
|
398
|
+
"actions": [ ... ]
|
|
399
|
+
}'
|
|
338
400
|
```
|
|
339
401
|
|
|
340
402
|
**Constraint:** All rules in the same `mutexGroup` must use identical `mutexMode` and `mutexStrategy`.
|
|
341
403
|
|
|
404
|
+
**`mutexGroup` is what turns mutex on.** Sending `mutexMode` without a `mutexGroup` is silently normalized to `NONE` —
|
|
405
|
+
there is no group to be exclusive within. Conversely, setting a `mutexGroup` without a `mutexMode` defaults to
|
|
406
|
+
`EXCLUSIVE`.
|
|
407
|
+
|
|
408
|
+
`mutexStrategy` currently accepts only `HIGHEST_PRIORITY` — the rule with the lowest priority
|
|
409
|
+
number in the group wins. `mutexMode: MAX_N` requires `mutexLimit`; omit it and the server
|
|
410
|
+
sets 2.
|
|
411
|
+
|
|
342
412
|
## Pre-Create Checklist
|
|
343
413
|
|
|
344
414
|
Before creating rules, always:
|
|
@@ -35,7 +35,7 @@ lexq groups list --api-key lexq_us_override_key
|
|
|
35
35
|
| **Policy Version** | A snapshot of rules within a group. Follows DRAFT → ACTIVE → ARCHIVED lifecycle. | Git branch / commit |
|
|
36
36
|
| **Policy Rule** | A condition + actions pair within a version. Evaluated in priority order. | if-then statement |
|
|
37
37
|
| **Fact Definition** | Input schema — declares available variables and their types (STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER). | Function parameter |
|
|
38
|
-
| **Deployment** | Promotes
|
|
38
|
+
| **Deployment** | Promotes an ACTIVE version to live traffic. Supports rollback and scheduled arming. | Production release |
|
|
39
39
|
| **Dry Run** | Tests a single input against a DRAFT or ACTIVE version without side effects. | Unit test |
|
|
40
40
|
| **Simulation** | Batch-tests a version against historical execution data. Compares with a baseline. | Integration test suite |
|
|
41
41
|
|
|
@@ -50,15 +50,15 @@ This is the typical lifecycle. **Always follow this order:**
|
|
|
50
50
|
4. lexq rules create → Add rules with conditions + actions
|
|
51
51
|
5. lexq analytics dry-run → Test with sample facts (validate before publish)
|
|
52
52
|
6. lexq deploy publish → DRAFT → ACTIVE (locks the version)
|
|
53
|
-
7. lexq
|
|
54
|
-
8. lexq
|
|
53
|
+
7. lexq analytics simulation → Batch-test against historical data with a baseline (optional)
|
|
54
|
+
8. lexq deploy live → Deploy ACTIVE version to production
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
### Critical Ordering Constraints
|
|
58
58
|
|
|
59
59
|
- **Cannot create rules without a DRAFT version.** Create the version first.
|
|
60
60
|
- **Cannot publish without at least one rule.** Add rules before publishing.
|
|
61
|
-
|
|
61
|
+
**Cannot modify an ACTIVE version.** Clone it to create a new DRAFT if changes are needed.
|
|
62
62
|
- **Cannot deploy a DRAFT version.** Must publish first (DRAFT → ACTIVE).
|
|
63
63
|
- **Always run `lexq analytics dry-run` before publishing.** This is your safety net.
|
|
64
64
|
|
|
@@ -80,19 +80,24 @@ Every command accepts these flags:
|
|
|
80
80
|
|
|
81
81
|
## Command Groups
|
|
82
82
|
|
|
83
|
-
| Group
|
|
84
|
-
|
|
85
|
-
| `auth`
|
|
86
|
-
| `status`
|
|
87
|
-
| `groups`
|
|
88
|
-
| `versions`
|
|
89
|
-
| `rules`
|
|
90
|
-
| `facts`
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
83
|
+
| Group | Commands | Description |
|
|
84
|
+
|-------------------------|----------------------------------------------------------------------------------------------------------------------------|---------------------------------|
|
|
85
|
+
| `auth` | `login`, `logout`, `whoami` | Authentication |
|
|
86
|
+
| `status` | (root) | API health check |
|
|
87
|
+
| `groups` | `list`, `get`, `create`, `update`, `delete`, `reorder` + `ab-test start\|stop\|adjust` | Policy group CRUD + A/B testing |
|
|
88
|
+
| `versions` | `list`, `get`, `create`, `update`, `delete`, `clone` | Version CRUD |
|
|
89
|
+
| `rules` | `list`, `get`, `create`, `update`, `delete`, `reorder`, `toggle` | Rule CRUD |
|
|
90
|
+
| `facts` | `list`, `create`, `update`, `delete` | Fact definition CRUD |
|
|
91
|
+
| `domain-templates` | `list`, `preview`, `apply` | Industry starter packs |
|
|
92
|
+
| `deploy` | `publish`, `live`, `rollback`, `undeploy`, `history`, `detail`, `overview`, `schedule`, `unschedule`, `schedules` | Deployment lifecycle |
|
|
93
|
+
| `analytics` | `dry-run`, `dry-run-compare`, `requirements`, `simulation start\|status\|list\|cancel\|export`, `dataset upload\|template` | Testing & analysis |
|
|
94
|
+
| `profile` | (root, takes `<groupId>`) | Per-rule latency profile |
|
|
95
|
+
| `history` | `list`, `get`, `stats` | Execution history |
|
|
96
|
+
| `replay` | `decision`, `start`, `list`, `get`, `cancel` | Decision replay |
|
|
97
|
+
| `provenance` | `get`, `reveal-audits` | Decision provenance + PII audit |
|
|
98
|
+
| `logs` | `list`, `get`, `action`, `bulk-action` | Failure log management |
|
|
99
|
+
| `webhook-subscriptions` | `list`, `get`, `save`, `delete`, `test` | Platform event webhooks |
|
|
100
|
+
| `serve` | `--mcp` | MCP server over stdio |
|
|
96
101
|
|
|
97
102
|
## Pagination
|
|
98
103
|
|
|
@@ -120,19 +125,27 @@ API errors return:
|
|
|
120
125
|
{
|
|
121
126
|
"result": "ERROR",
|
|
122
127
|
"message": "Policy version not found.",
|
|
123
|
-
"
|
|
128
|
+
"errorCode": "P-002"
|
|
124
129
|
}
|
|
125
130
|
```
|
|
126
131
|
|
|
127
|
-
|
|
132
|
+
`errorCode` is a stable identifier of the form `<domain>-<number>`. `message` is the
|
|
133
|
+
human-readable explanation and is localized by `Accept-Language`. **Branch on `errorCode`, never
|
|
134
|
+
on `message`.**
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
|
132
|
-
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
+
Prefixes you will encounter through the CLI:
|
|
137
|
+
|
|
138
|
+
| Prefix | Domain | Example cause |
|
|
139
|
+
|--------|-----------------------|------------------------------------------------|
|
|
140
|
+
| `C-` | Common validation | Malformed or missing request field |
|
|
141
|
+
| `A-` | Auth | Invalid or missing API key |
|
|
142
|
+
| `P-` | Policy group/version | Not found, wrong lifecycle state, already live |
|
|
143
|
+
| `ACT-` | Action parameters | Missing or invalid action parameter |
|
|
144
|
+
| `FD-` | Fact definitions | Duplicate key, system fact immutable |
|
|
145
|
+
| `AN-` | Analytics | Dry-run or simulation failure |
|
|
146
|
+
| `FL-` | Failure logs | Log not found |
|
|
147
|
+
| `WH-` | Webhook subscriptions | Invalid URL, delivery failure |
|
|
148
|
+
| `I-` | Idempotency | Duplicate idempotency key |
|
|
136
149
|
|
|
137
150
|
## Important Conventions
|
|
138
151
|
|
|
@@ -140,6 +153,13 @@ API errors return:
|
|
|
140
153
|
2. **IDs are UUIDs.** Always copy the full ID from list/create output — do not guess.
|
|
141
154
|
3. **Dates use ISO 8601.** Example: `2025-01-01T00:00:00Z`. Time zone is UTC.
|
|
142
155
|
4. **JSON bodies via `--json`.** Most create/update commands accept `--json '<body>'` for the request body.
|
|
143
|
-
5. **File input via `--file`.**
|
|
156
|
+
5. **File input via `--file`.** `analytics dry-run`, `dry-run-compare`, `simulation start` accept
|
|
157
|
+
`--file path/to/body.json` as an alternative to `--json`. `analytics dataset upload` requires
|
|
158
|
+
`--file` (CSV or JSON). `simulation export` and `dataset template` write output with `--output`.
|
|
144
159
|
6. **Confirmation prompts.** Destructive operations (delete, cancel, undeploy) prompt for confirmation. Use `--force` to
|
|
145
|
-
skip in automation.
|
|
160
|
+
skip in automation.
|
|
161
|
+
|
|
162
|
+
## Skill Formatting
|
|
163
|
+
|
|
164
|
+
Catalog-style skills (`lexq-recipes`) separate independent items with `---`. Narrative skills do
|
|
165
|
+
not use it at all. Never mix both in one file.
|
|
@@ -78,17 +78,19 @@ lexq analytics dry-run --version-id <vid> --json '{
|
|
|
78
78
|
| Flag | Description | Default |
|
|
79
79
|
|-----------------|-----------------------------------------------------|---------|
|
|
80
80
|
| `--debug` | Include execution traces (which rules matched, why) | `false` |
|
|
81
|
-
| `--mock` | Mock external calls (webhooks, integrations) | `false` |
|
|
82
81
|
| `--file <path>` | Read request body from file instead of `--json` | — |
|
|
83
82
|
|
|
84
|
-
### Recommended: Always Use `--debug
|
|
83
|
+
### Recommended: Always Use `--debug`
|
|
85
84
|
|
|
86
85
|
```bash
|
|
87
|
-
lexq analytics dry-run --version-id <vid> --debug --
|
|
86
|
+
lexq analytics dry-run --version-id <vid> --debug --json '{
|
|
88
87
|
"facts": { "payment_amount": 150000, "customer_tier": "VIP" }
|
|
89
88
|
}'
|
|
90
89
|
```
|
|
91
90
|
|
|
91
|
+
Dry run has no side effects — actions only mutate the fact map in memory. There is nothing
|
|
92
|
+
external to mock.
|
|
93
|
+
|
|
92
94
|
### Response Structure
|
|
93
95
|
|
|
94
96
|
```json
|
|
@@ -145,27 +147,32 @@ lexq analytics dry-run --version-id <vid> --debug --mock --json '{
|
|
|
145
147
|
|
|
146
148
|
Each trace carries a `status` (what happened) and a `reasonCode` (why).
|
|
147
149
|
|
|
148
|
-
| Status
|
|
149
|
-
|
|
150
|
-
| `SELECTED`
|
|
151
|
-
| `NO_MATCH`
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
154
|
-
|
|
150
|
+
| Status | Meaning |
|
|
151
|
+
|------------|---------------------------------------------------------------------------------|
|
|
152
|
+
| `SELECTED` | Rule matched and its actions fired |
|
|
153
|
+
| `NO_MATCH` | Condition did not match, or could not be evaluated |
|
|
154
|
+
| `BLOCKED` | Matched but lost conflict resolution — see `reasonCode` for which round and why |
|
|
155
|
+
| `ERROR` | Action execution failed |
|
|
156
|
+
|
|
157
|
+
`BLOCKED` is unrelated to the `BLOCK` action. A `BLOCK` action writes the `is_blocked` fact and its own rule stays
|
|
158
|
+
`SELECTED`; `BLOCKED` means the rule was dropped by activation-group or mutex competition.
|
|
155
159
|
|
|
156
160
|
### Reading Reason Codes
|
|
157
161
|
|
|
158
|
-
| Code
|
|
159
|
-
|
|
160
|
-
| `FINAL_WINNER`
|
|
161
|
-
| `CONDITION_MISMATCH`
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
168
|
-
|
|
162
|
+
| Code | Meaning |
|
|
163
|
+
|-----------------------|----------------------------------------------------------|
|
|
164
|
+
| `FINAL_WINNER` | Successfully executed |
|
|
165
|
+
| `CONDITION_MISMATCH` | Condition not satisfied, or could not be evaluated |
|
|
166
|
+
| `MUTEX_PRIORITY_LOST` | Another rule in the same mutex group had higher priority |
|
|
167
|
+
| `MUTEX_LIMIT_REACHED` | Mutex group's max rules already fired |
|
|
168
|
+
| `GROUP_PRIORITY_LOST` | Another group in the same activation group won |
|
|
169
|
+
| `GROUP_LIMIT_REACHED` | Group's `executionLimit` reached |
|
|
170
|
+
| `ACTION_ERROR` | Action execution failed (e.g. required fact absent) |
|
|
171
|
+
| `ENGINE_ERROR` | Internal engine failure |
|
|
172
|
+
|
|
173
|
+
A version outside its effective date range is filtered **before** evaluation — no trace is produced for it at all. If a
|
|
174
|
+
rule you expect never appears in `decisionTraces`, check the version's `effectiveFrom` / `effectiveTo` with
|
|
175
|
+
`lexq versions get`.
|
|
169
176
|
|
|
170
177
|
#### `reasonDetail` on unevaluable conditions
|
|
171
178
|
|
|
@@ -238,19 +245,19 @@ lexq analytics simulation start --json '{
|
|
|
238
245
|
```bash
|
|
239
246
|
# 1. Download template (optional)
|
|
240
247
|
lexq analytics dataset template \
|
|
241
|
-
--group-id
|
|
248
|
+
--group-id <gid> --version-id <vid> --format csv --output template.csv
|
|
242
249
|
|
|
243
250
|
# 2. Upload dataset
|
|
244
251
|
lexq analytics dataset upload --file ./my-data.csv
|
|
245
|
-
# → path: datasets
|
|
252
|
+
# → path: datasets/<tenantId>/a1b2c3d4e5f6.csv
|
|
246
253
|
|
|
247
254
|
# 3. Start simulation with uploaded path
|
|
248
255
|
lexq analytics simulation start --json '{
|
|
249
|
-
"policyVersionId": "",
|
|
256
|
+
"policyVersionId": "<vid>",
|
|
250
257
|
"dataset": {
|
|
251
258
|
"type": "UPLOADED",
|
|
252
259
|
"source": "S3_BUCKET",
|
|
253
|
-
"path": "
|
|
260
|
+
"path": "<path returned by dataset upload>"
|
|
254
261
|
},
|
|
255
262
|
"options": { "includeRuleStats": true, "maxRecords": 10000 }
|
|
256
263
|
}'
|
|
@@ -259,13 +266,6 @@ lexq analytics simulation start --json '{
|
|
|
259
266
|
**CSV format:** Header row with fact keys, data rows with values. Types auto-detected.
|
|
260
267
|
**JSON format:** Array of objects `[{"key": "value"}, ...]`
|
|
261
268
|
|
|
262
|
-
### MCP — Dataset Tools
|
|
263
|
-
|
|
264
|
-
```
|
|
265
|
-
lexq_dataset_template → Get sample CSV/JSON based on version's required facts
|
|
266
|
-
lexq_dataset_upload → Upload inline CSV/JSON content to S3, returns path
|
|
267
|
-
```
|
|
268
|
-
|
|
269
269
|
### Check Status (Poll)
|
|
270
270
|
|
|
271
271
|
```bash
|
|
@@ -352,7 +352,7 @@ lexq analytics simulation export --id <simulationId> --format csv --output resul
|
|
|
352
352
|
lexq analytics requirements --group-id <gid> --version-id <vid>
|
|
353
353
|
|
|
354
354
|
# 2. Dry-run with representative inputs
|
|
355
|
-
lexq analytics dry-run --version-id <vid> --debug --
|
|
355
|
+
lexq analytics dry-run --version-id <vid> --debug --json '{
|
|
356
356
|
"facts": { "payment_amount": 150000, "customer_tier": "VIP" }
|
|
357
357
|
}'
|
|
358
358
|
|