@lexq/cli 1.1.3 → 1.1.5
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/README.md +28 -28
- package/dist/index.js +30 -16
- package/dist/mcp/register.js +19 -9
- package/package.json +1 -1
- package/skills/lexq-rules/SKILL.md +8 -4
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# LexQ CLI
|
|
2
2
|
|
|
3
3
|
> **The Decision Operations Platform for engineering teams.**
|
|
4
|
-
> CLI and MCP server for [LexQ](https://lexq.io)
|
|
4
|
+
> CLI and MCP server for [LexQ](https://lexq.io). Move business rules out of
|
|
5
5
|
> your deploy pipeline, prove every change with Impact Simulation, and ship without
|
|
6
6
|
> a git push.
|
|
7
7
|
|
|
@@ -14,20 +14,17 @@
|
|
|
14
14
|
|
|
15
15
|
## Why LexQ?
|
|
16
16
|
|
|
17
|
-
Your business rules
|
|
18
|
-
change often. But every change ships through the same PR → review →
|
|
19
|
-
→ deploy cycle as your core application code
|
|
20
|
-
|
|
17
|
+
Your business rules, such as pricing, promotions, fee logic, and eligibility
|
|
18
|
+
checks, change often. But every change ships through the same PR → review →
|
|
19
|
+
staging → deploy cycle as your core application code, so even a small change
|
|
20
|
+
waits for the next release.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
**LexQ keeps those rules out of your code.** Your service calls the LexQ API to
|
|
23
|
+
evaluate them. You change rules in a visual console or through this CLI, test
|
|
24
|
+
each change with Impact Simulation against past executions or a dataset you
|
|
25
|
+
upload, and deploy them without an application release.
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
them in a visual console or through this CLI. You prove every change with
|
|
27
|
-
Impact Simulation against real execution data. You deploy without touching
|
|
28
|
-
your codebase.
|
|
29
|
-
|
|
30
|
-
Every decision leaves a full audit trace.
|
|
27
|
+
Every decision leaves a full audit trail.
|
|
31
28
|
|
|
32
29
|
## Install
|
|
33
30
|
|
|
@@ -67,19 +64,22 @@ lexq deploy publish --group-id <GROUP_ID> --version-id <VERSION_ID> --memo "v1"
|
|
|
67
64
|
lexq deploy live --group-id <GROUP_ID> --version-id <VERSION_ID> --memo "Initial deploy"
|
|
68
65
|
```
|
|
69
66
|
|
|
70
|
-
## For AI Agents
|
|
67
|
+
## For AI Agents
|
|
68
|
+
|
|
69
|
+
Claude, Cursor, and other MCP-compatible agents can use the Model Context
|
|
70
|
+
Protocol to manage policy groups, versions, rules, and facts, run simulations
|
|
71
|
+
and replays, deploy versions, and read execution history.
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
before production.
|
|
73
|
+
Approval happens in your MCP client, which decides which tool calls you confirm.
|
|
74
|
+
The deploy, rollback, and undeploy tools are marked as destructive, so a client
|
|
75
|
+
can ask you before running them.
|
|
76
76
|
|
|
77
|
-
### Claude.ai (
|
|
77
|
+
### Claude.ai (cloud, no install)
|
|
78
78
|
|
|
79
|
-
1. **
|
|
80
|
-
2.
|
|
81
|
-
3.
|
|
82
|
-
4.
|
|
79
|
+
1. **Customize → Connectors → + Add → Add custom connector**
|
|
80
|
+
2. Name it, enter `https://mcp.lexq.io`, and choose **Sign in now**
|
|
81
|
+
3. On the LexQ page that opens, sign in and generate a new API key for MCP, or choose **I already have an API key** and paste an existing one
|
|
82
|
+
4. The tools are now available in every conversation
|
|
83
83
|
|
|
84
84
|
### Remote (Streamable HTTP)
|
|
85
85
|
|
|
@@ -170,8 +170,8 @@ keeps working.
|
|
|
170
170
|
|
|
171
171
|
## AI Agent Skills
|
|
172
172
|
|
|
173
|
-
LexQ CLI ships with **AI Agent Skills
|
|
174
|
-
|
|
173
|
+
LexQ CLI ships with **AI Agent Skills**: structured documentation that tells
|
|
174
|
+
agents *how* to use each tool.
|
|
175
175
|
|
|
176
176
|
```
|
|
177
177
|
skills/
|
|
@@ -242,9 +242,9 @@ Config is stored at `~/.lexq/config.json`:
|
|
|
242
242
|
}
|
|
243
243
|
```
|
|
244
244
|
|
|
245
|
-
The file holds an API key in plain text
|
|
246
|
-
|
|
247
|
-
|
|
245
|
+
The file holds an API key in plain text. It is saved with mode `0600` inside a `0700`
|
|
246
|
+
directory, so only its owner can read it. If an older version created it with looser
|
|
247
|
+
permissions, the CLI tightens them the next time it saves the file.
|
|
248
248
|
|
|
249
249
|
### Environment variables
|
|
250
250
|
|
package/dist/index.js
CHANGED
|
@@ -1058,7 +1058,7 @@ ${data.length} total`);
|
|
|
1058
1058
|
Action Types:
|
|
1059
1059
|
MUTATE_FACT { targetVar, operator, method, operand, refVar?, rounding? }
|
|
1060
1060
|
SET_FACT { targetVar, value }
|
|
1061
|
-
BLOCK { reason }
|
|
1061
|
+
BLOCK { reason? }
|
|
1062
1062
|
|
|
1063
1063
|
refVar is the percentage base and is optional — omit to use targetVar itself.
|
|
1064
1064
|
It is only valid in PERCENTAGE × {ASSIGN, ADD, SUB}.
|
|
@@ -1302,7 +1302,8 @@ function registerFactCommands(program) {
|
|
|
1302
1302
|
delete Remove a fact definition
|
|
1303
1303
|
action-metadata Show action runtime fact metadata
|
|
1304
1304
|
|
|
1305
|
-
|
|
1305
|
+
Every tenant starts with userId and userTags, and with the system facts
|
|
1306
|
+
isBlocked and blockReason, which only the BLOCK action writes.
|
|
1306
1307
|
`
|
|
1307
1308
|
);
|
|
1308
1309
|
facts.command("list").description("List fact definitions").option("--keyword <keyword>", "Filter by keyword").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
|
|
@@ -1443,7 +1444,8 @@ ${data.length} unregistered`);
|
|
|
1443
1444
|
"after",
|
|
1444
1445
|
dedent6`
|
|
1445
1446
|
|
|
1446
|
-
System facts accept name, description,
|
|
1447
|
+
System facts (isBlocked, blockReason) accept changes to name, description, the PII flag,
|
|
1448
|
+
and the value domain. --required is ignored, and the type cannot change (FD-003).
|
|
1447
1449
|
|
|
1448
1450
|
Examples:
|
|
1449
1451
|
$ lexq facts update --id <factId> --name "Updated Name" --required
|
|
@@ -3939,11 +3941,21 @@ function registerRuleTools(server, callApi) {
|
|
|
3939
3941
|
requires operand !== 0.
|
|
3940
3942
|
- SET_FACT: { targetVar: string, value: string|number|boolean } targetVar must be a
|
|
3941
3943
|
registered fact (ACT-032 otherwise). The request does not have to send it: SET_FACT is
|
|
3942
|
-
the only action
|
|
3944
|
+
the only action whose targetVar may be absent from the input facts. MUTATE_FACT requires
|
|
3943
3945
|
its target to be present in the input facts.
|
|
3944
|
-
- BLOCK: { reason
|
|
3946
|
+
- BLOCK: { reason?: string } Records a rejection decision. It does NOT halt rule execution —
|
|
3945
3947
|
subsequent actions and subsequent winning rules still run. Enforcement is the caller's
|
|
3946
|
-
responsibility; the decision surfaces as
|
|
3948
|
+
responsibility; the decision surfaces as isBlocked (true) and blockReason (reason, or
|
|
3949
|
+
"Policy Violation" when omitted).
|
|
3950
|
+
Only BLOCK writes those two keys: saving or publishing a rule whose SET_FACT or
|
|
3951
|
+
MUTATE_FACT targets either one fails with ACT-033.
|
|
3952
|
+
|
|
3953
|
+
Evaluation order: every rule's condition is checked against the input facts before any
|
|
3954
|
+
action runs, so a condition never sees a value an action writes in the same request. Then
|
|
3955
|
+
the actions of the winning rules run in priority order. Each action works on the values
|
|
3956
|
+
the actions before it left, in its own rule or an earlier one. To test a value an action
|
|
3957
|
+
writes, send that value as an input fact in a second request. If a rule should run
|
|
3958
|
+
whenever another one does, put its actions in that rule instead.
|
|
3947
3959
|
|
|
3948
3960
|
RoundingOption (optional, MUTATE_FACT only): { scale: integer (0..${MAX_ROUNDING_SCALE}), mode?: "HALF_UP"|"HALF_DOWN"|"HALF_EVEN"|"FLOOR"|"CEILING"|"DOWN"|"UP" } mode defaults to HALF_UP. When omitted, calculator output is preserved at full precision (lossless).
|
|
3949
3961
|
`,
|
|
@@ -4104,7 +4116,7 @@ function registerFactTools(server, callApi) {
|
|
|
4104
4116
|
{
|
|
4105
4117
|
title: "Update Fact Definition",
|
|
4106
4118
|
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
4107
|
-
description: "Update a fact definition. The key is immutable. The type can change only while no rule references the fact; if any does, the call fails with FD-007 and reports the count. Rules in deleted groups do not count. Only the fields you send are changed. System facts accept name, description, and
|
|
4119
|
+
description: "Update a fact definition. The key is immutable. The type can change only while no rule references the fact; if any does, the call fails with FD-007 and reports the count. Rules in deleted groups do not count. Only the fields you send are changed. System facts (isBlocked, blockReason) accept changes to name, description, PII, and the value domain; isRequired is ignored, and their type cannot change (FD-003).",
|
|
4108
4120
|
inputSchema: z5.object({
|
|
4109
4121
|
factId: z5.string().uuid().describe("Fact definition ID"),
|
|
4110
4122
|
name: z5.string().optional().describe("Display name"),
|
|
@@ -4144,7 +4156,7 @@ function registerFactTools(server, callApi) {
|
|
|
4144
4156
|
{
|
|
4145
4157
|
title: "Get Action Runtime Fact Metadata",
|
|
4146
4158
|
annotations: { readOnlyHint: true },
|
|
4147
|
-
description: "Retrieve runtime fact requirements per Action type. For each Action, shows which input facts must be present in the execution payload \u2014 e.g. MUTATE_FACT always requires its targetVar fact, plus refVar when one is specified. The factRequired flag describes the FACT, not the parameter: refVar is an optional parameter, but if you specify it the named fact must exist. A required fact absent at runtime throws \u2014 the engine never defaults to 0. These facts must be sent in the request (P-015 otherwise), even when an earlier action in the same rule writes them. SET_FACT requires no input fact: it is the only action
|
|
4159
|
+
description: "Retrieve runtime fact requirements per Action type. For each Action, shows which input facts must be present in the execution payload \u2014 e.g. MUTATE_FACT always requires its targetVar fact, plus refVar when one is specified. The factRequired flag describes the FACT, not the parameter: refVar is an optional parameter, but if you specify it the named fact must exist. A required fact absent at runtime throws \u2014 the engine never defaults to 0. These facts must be sent in the request (P-015 otherwise), even when an earlier action in the same rule writes them. SET_FACT requires no input fact: it is the only action whose targetVar the request does not have to send, and that targetVar must be a registered fact (ACT-032). Static data, safe to cache in-session.",
|
|
4148
4160
|
inputSchema: z5.object({})
|
|
4149
4161
|
},
|
|
4150
4162
|
async () => callApi("GET", "schema/action-metadata")
|
|
@@ -5000,7 +5012,7 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
5000
5012
|
{
|
|
5001
5013
|
title: "List Domain Templates",
|
|
5002
5014
|
annotations: { readOnlyHint: true },
|
|
5003
|
-
description: "List all domain templates. A domain template is a
|
|
5015
|
+
description: "List all domain templates. A domain template is a starter pack of fact definitions and sample rules for a common decision, such as checkout pricing (ECOMMERCE) or transfer approval (FINTECH). Each entry reports its key, whether it can be applied (isAvailable), and how many facts and sample rules it provisions. Call this before preview or apply to see which templates exist.",
|
|
5004
5016
|
inputSchema: z14.object({})
|
|
5005
5017
|
},
|
|
5006
5018
|
async () => callApi("GET", "domain-templates")
|
|
@@ -5010,10 +5022,10 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
5010
5022
|
{
|
|
5011
5023
|
title: "Preview Domain Template",
|
|
5012
5024
|
annotations: { readOnlyHint: true },
|
|
5013
|
-
description: "Preview exactly what a domain template will provision before applying it: the fact definitions it registers, the sample rules it creates, and an apply plan. This is a read-only dry run
|
|
5025
|
+
description: "Preview exactly what a domain template will provision before applying it: the fact definitions it registers (an input with a constraint carries its allowed values or range), the sample rules it creates with a description of each, and an apply plan. This is a read-only dry run; nothing is created. factConflicts lists keys this tenant already has with a different type, or with different allowed values or a different range on an input fact. While it is not empty, apply fails with P-061 and creates nothing: delete those facts or change them to match the template, then apply. plan is null for a template that cannot be applied yet.",
|
|
5014
5026
|
inputSchema: z14.object({
|
|
5015
5027
|
template: z14.string().describe(
|
|
5016
|
-
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see
|
|
5028
|
+
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see the keys."
|
|
5017
5029
|
)
|
|
5018
5030
|
})
|
|
5019
5031
|
},
|
|
@@ -5024,7 +5036,7 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
5024
5036
|
{
|
|
5025
5037
|
title: "Apply Domain Template",
|
|
5026
5038
|
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
5027
|
-
description: "Apply a domain template to the current tenant. Creates the template's fact definitions and a new policy group pre-populated with its sample rules as a DRAFT version.
|
|
5039
|
+
description: "Apply a domain template to the current tenant. Creates the template's fact definitions and a new policy group pre-populated with its sample rules as a DRAFT version. Apply never overwrites existing schema: a key that already exists with the same definition is kept as it is. Run lexq_domain_templates_preview first. If its factConflicts is not empty, apply fails with P-061 and creates nothing until those facts are deleted or changed to match the template. A template whose isAvailable is false cannot be applied.",
|
|
5028
5040
|
inputSchema: z14.object({
|
|
5029
5041
|
template: z14.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
|
|
5030
5042
|
customName: z14.string().optional().describe(
|
|
@@ -5141,7 +5153,7 @@ function registerDomainTemplateCommands(program) {
|
|
|
5141
5153
|
apply Apply a template to the current tenant
|
|
5142
5154
|
|
|
5143
5155
|
Workflow: list → preview → apply
|
|
5144
|
-
|
|
5156
|
+
Run "list" to see every template and whether it can be applied.
|
|
5145
5157
|
`
|
|
5146
5158
|
);
|
|
5147
5159
|
templates.command("list").description("List available domain templates").action(async () => {
|
|
@@ -5208,10 +5220,12 @@ function registerDomainTemplateCommands(program) {
|
|
|
5208
5220
|
dedent18`
|
|
5209
5221
|
|
|
5210
5222
|
Creates the template's fact definitions and a new DRAFT policy group
|
|
5211
|
-
populated with its sample rules.
|
|
5212
|
-
|
|
5223
|
+
populated with its sample rules. A fact that already exists with the
|
|
5224
|
+
same definition is kept as it is, so apply never overwrites your schema.
|
|
5213
5225
|
|
|
5214
|
-
Run "preview" first to review what will be created.
|
|
5226
|
+
Run "preview" first to review what will be created. If it lists
|
|
5227
|
+
factConflicts, apply fails with P-061 and creates nothing: delete those
|
|
5228
|
+
facts or change them to match the template first.
|
|
5215
5229
|
|
|
5216
5230
|
Example:
|
|
5217
5231
|
$ lexq domain-templates apply --template ECOMMERCE
|
package/dist/mcp/register.js
CHANGED
|
@@ -483,11 +483,21 @@ function registerRuleTools(server, callApi) {
|
|
|
483
483
|
requires operand !== 0.
|
|
484
484
|
- SET_FACT: { targetVar: string, value: string|number|boolean } targetVar must be a
|
|
485
485
|
registered fact (ACT-032 otherwise). The request does not have to send it: SET_FACT is
|
|
486
|
-
the only action
|
|
486
|
+
the only action whose targetVar may be absent from the input facts. MUTATE_FACT requires
|
|
487
487
|
its target to be present in the input facts.
|
|
488
|
-
- BLOCK: { reason
|
|
488
|
+
- BLOCK: { reason?: string } Records a rejection decision. It does NOT halt rule execution —
|
|
489
489
|
subsequent actions and subsequent winning rules still run. Enforcement is the caller's
|
|
490
|
-
responsibility; the decision surfaces as
|
|
490
|
+
responsibility; the decision surfaces as isBlocked (true) and blockReason (reason, or
|
|
491
|
+
"Policy Violation" when omitted).
|
|
492
|
+
Only BLOCK writes those two keys: saving or publishing a rule whose SET_FACT or
|
|
493
|
+
MUTATE_FACT targets either one fails with ACT-033.
|
|
494
|
+
|
|
495
|
+
Evaluation order: every rule's condition is checked against the input facts before any
|
|
496
|
+
action runs, so a condition never sees a value an action writes in the same request. Then
|
|
497
|
+
the actions of the winning rules run in priority order. Each action works on the values
|
|
498
|
+
the actions before it left, in its own rule or an earlier one. To test a value an action
|
|
499
|
+
writes, send that value as an input fact in a second request. If a rule should run
|
|
500
|
+
whenever another one does, put its actions in that rule instead.
|
|
491
501
|
|
|
492
502
|
RoundingOption (optional, MUTATE_FACT only): { scale: integer (0..${MAX_ROUNDING_SCALE}), mode?: "HALF_UP"|"HALF_DOWN"|"HALF_EVEN"|"FLOOR"|"CEILING"|"DOWN"|"UP" } mode defaults to HALF_UP. When omitted, calculator output is preserved at full precision (lossless).
|
|
493
503
|
`,
|
|
@@ -652,7 +662,7 @@ function registerFactTools(server, callApi) {
|
|
|
652
662
|
{
|
|
653
663
|
title: "Update Fact Definition",
|
|
654
664
|
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
655
|
-
description: "Update a fact definition. The key is immutable. The type can change only while no rule references the fact; if any does, the call fails with FD-007 and reports the count. Rules in deleted groups do not count. Only the fields you send are changed. System facts accept name, description, and
|
|
665
|
+
description: "Update a fact definition. The key is immutable. The type can change only while no rule references the fact; if any does, the call fails with FD-007 and reports the count. Rules in deleted groups do not count. Only the fields you send are changed. System facts (isBlocked, blockReason) accept changes to name, description, PII, and the value domain; isRequired is ignored, and their type cannot change (FD-003).",
|
|
656
666
|
inputSchema: z5.object({
|
|
657
667
|
factId: z5.string().uuid().describe("Fact definition ID"),
|
|
658
668
|
name: z5.string().optional().describe("Display name"),
|
|
@@ -692,7 +702,7 @@ function registerFactTools(server, callApi) {
|
|
|
692
702
|
{
|
|
693
703
|
title: "Get Action Runtime Fact Metadata",
|
|
694
704
|
annotations: { readOnlyHint: true },
|
|
695
|
-
description: "Retrieve runtime fact requirements per Action type. For each Action, shows which input facts must be present in the execution payload \u2014 e.g. MUTATE_FACT always requires its targetVar fact, plus refVar when one is specified. The factRequired flag describes the FACT, not the parameter: refVar is an optional parameter, but if you specify it the named fact must exist. A required fact absent at runtime throws \u2014 the engine never defaults to 0. These facts must be sent in the request (P-015 otherwise), even when an earlier action in the same rule writes them. SET_FACT requires no input fact: it is the only action
|
|
705
|
+
description: "Retrieve runtime fact requirements per Action type. For each Action, shows which input facts must be present in the execution payload \u2014 e.g. MUTATE_FACT always requires its targetVar fact, plus refVar when one is specified. The factRequired flag describes the FACT, not the parameter: refVar is an optional parameter, but if you specify it the named fact must exist. A required fact absent at runtime throws \u2014 the engine never defaults to 0. These facts must be sent in the request (P-015 otherwise), even when an earlier action in the same rule writes them. SET_FACT requires no input fact: it is the only action whose targetVar the request does not have to send, and that targetVar must be a registered fact (ACT-032). Static data, safe to cache in-session.",
|
|
696
706
|
inputSchema: z5.object({})
|
|
697
707
|
},
|
|
698
708
|
async () => callApi("GET", "schema/action-metadata")
|
|
@@ -1548,7 +1558,7 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
1548
1558
|
{
|
|
1549
1559
|
title: "List Domain Templates",
|
|
1550
1560
|
annotations: { readOnlyHint: true },
|
|
1551
|
-
description: "List all domain templates. A domain template is a
|
|
1561
|
+
description: "List all domain templates. A domain template is a starter pack of fact definitions and sample rules for a common decision, such as checkout pricing (ECOMMERCE) or transfer approval (FINTECH). Each entry reports its key, whether it can be applied (isAvailable), and how many facts and sample rules it provisions. Call this before preview or apply to see which templates exist.",
|
|
1552
1562
|
inputSchema: z14.object({})
|
|
1553
1563
|
},
|
|
1554
1564
|
async () => callApi("GET", "domain-templates")
|
|
@@ -1558,10 +1568,10 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
1558
1568
|
{
|
|
1559
1569
|
title: "Preview Domain Template",
|
|
1560
1570
|
annotations: { readOnlyHint: true },
|
|
1561
|
-
description: "Preview exactly what a domain template will provision before applying it: the fact definitions it registers, the sample rules it creates, and an apply plan. This is a read-only dry run
|
|
1571
|
+
description: "Preview exactly what a domain template will provision before applying it: the fact definitions it registers (an input with a constraint carries its allowed values or range), the sample rules it creates with a description of each, and an apply plan. This is a read-only dry run; nothing is created. factConflicts lists keys this tenant already has with a different type, or with different allowed values or a different range on an input fact. While it is not empty, apply fails with P-061 and creates nothing: delete those facts or change them to match the template, then apply. plan is null for a template that cannot be applied yet.",
|
|
1562
1572
|
inputSchema: z14.object({
|
|
1563
1573
|
template: z14.string().describe(
|
|
1564
|
-
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see
|
|
1574
|
+
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see the keys."
|
|
1565
1575
|
)
|
|
1566
1576
|
})
|
|
1567
1577
|
},
|
|
@@ -1572,7 +1582,7 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
1572
1582
|
{
|
|
1573
1583
|
title: "Apply Domain Template",
|
|
1574
1584
|
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
1575
|
-
description: "Apply a domain template to the current tenant. Creates the template's fact definitions and a new policy group pre-populated with its sample rules as a DRAFT version.
|
|
1585
|
+
description: "Apply a domain template to the current tenant. Creates the template's fact definitions and a new policy group pre-populated with its sample rules as a DRAFT version. Apply never overwrites existing schema: a key that already exists with the same definition is kept as it is. Run lexq_domain_templates_preview first. If its factConflicts is not empty, apply fails with P-061 and creates nothing until those facts are deleted or changed to match the template. A template whose isAvailable is false cannot be applied.",
|
|
1576
1586
|
inputSchema: z14.object({
|
|
1577
1587
|
template: z14.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
|
|
1578
1588
|
customName: z14.string().optional().describe(
|
package/package.json
CHANGED
|
@@ -182,7 +182,7 @@ Each rule can have multiple actions. Actions fire sequentially.
|
|
|
182
182
|
|---------------|--------------------------------------------|----------------------------------------------------------------------|
|
|
183
183
|
| `MUTATE_FACT` | Arithmetic change to a numeric fact | `targetVar`, `operator`, `method`, `operand`, `refVar?`, `rounding?` |
|
|
184
184
|
| `SET_FACT` | Assign a literal value to a registered fact | `targetVar`, `value` |
|
|
185
|
-
| `BLOCK` | Record a rejection decision | `reason
|
|
185
|
+
| `BLOCK` | Record a rejection decision | `reason?` |
|
|
186
186
|
|
|
187
187
|
### `MUTATE_FACT` parameters
|
|
188
188
|
|
|
@@ -247,9 +247,13 @@ request didn't send" is `SET_FACT`'s job.
|
|
|
247
247
|
|
|
248
248
|
### `BLOCK` does not halt execution
|
|
249
249
|
|
|
250
|
-
`BLOCK` records a rejection decision by writing
|
|
251
|
-
|
|
252
|
-
read `isBlocked` from the response.
|
|
250
|
+
`BLOCK` records a rejection decision by writing `isBlocked` (`true`) and `blockReason` (`reason`,
|
|
251
|
+
or `Policy Violation` when omitted). Subsequent actions in the same rule and subsequent winning
|
|
252
|
+
rules still run. Enforcement is the caller's responsibility — read `isBlocked` from the response.
|
|
253
|
+
|
|
254
|
+
Only `BLOCK` writes those two keys. Saving or publishing a rule whose `SET_FACT` or
|
|
255
|
+
`MUTATE_FACT` targets either one fails with `ACT-033`. No condition sees what `BLOCK` writes
|
|
256
|
+
in the same request: every condition is checked against the input facts before any action runs.
|
|
253
257
|
|
|
254
258
|
### Action Example: 10% Discount via MUTATE_FACT
|
|
255
259
|
|