@lexq/cli 1.1.0 → 1.1.1

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/dist/index.js CHANGED
@@ -1328,7 +1328,9 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1328
1328
  dedent6`
1329
1329
 
1330
1330
  Facts used in a version's rules that have no definition yet (read-only).
1331
- Does not block publish/deploy — register them to enable validation.
1331
+ Keys a rule only reads do not block publish/deploy; register them to enable
1332
+ validation. A SET_FACT or MUTATE_FACT targetVar must already be registered:
1333
+ saving or publishing fails with ACT-032 otherwise.
1332
1334
 
1333
1335
  Example:
1334
1336
  $ lexq facts unregistered --group-id <gid> --version-id <vid> --format table
@@ -3842,7 +3844,12 @@ function registerRuleTools(server, callApi) {
3842
3844
  If a required key is missing, ask the user to confirm the type, isRequired, and description
3843
3845
  before calling lexq_facts_create — registering facts enables type validation, Console UI
3844
3846
  autocomplete, and the dry-run requirements analyzer.
3845
-
3847
+
3848
+ An action's targetVar (SET_FACT, MUTATE_FACT) must be a registered fact. Saving or
3849
+ publishing a rule whose targetVar is not registered fails with ACT-032, so register it
3850
+ with lexq_facts_create first. Keys a rule only reads (condition fields, refVar) may stay
3851
+ unregistered.
3852
+
3846
3853
  After saving, lexq_facts_unregistered lists any keys this version references but has not
3847
3854
  defined (non-blocking, version-wide) — use it to decide what to register.
3848
3855
 
@@ -3871,8 +3878,9 @@ function registerRuleTools(server, callApi) {
3871
3878
 
3872
3879
  Action parameter schemas:
3873
3880
  - MUTATE_FACT: { targetVar: string, operator: "ASSIGN"|"ADD"|"SUB"|"MUL"|"DIV", method: "PERCENTAGE"|"AMOUNT", operand: number, refVar?: string, rounding?: RoundingOption }
3874
- targetVar is the fact this action reads and writes. It must exist in facts at execution
3875
- time as a number — supplied as an input fact or written by a prior action in this rule.
3881
+ targetVar is the fact this action reads and writes. It must be a registered fact
3882
+ (ACT-032 otherwise), and the request must send it (P-015 otherwise). Its value must be
3883
+ a number when the action runs.
3876
3884
  A missing required fact throws (no 0 default).
3877
3885
  operand is the arithmetic operand; the unit is dictated by method (percent when
3878
3886
  PERCENTAGE, absolute amount when AMOUNT). Ranges are not constrained — negative values
@@ -3890,8 +3898,10 @@ function registerRuleTools(server, callApi) {
3890
3898
  DIV targetVar /= operand | invalid
3891
3899
  Constraints: DIV + PERCENTAGE is invalid (use MUL with the inverse). DIV + AMOUNT
3892
3900
  requires operand !== 0.
3893
- - SET_FACT: { targetVar: string, value: string|number|boolean } Creates the fact if absent
3894
- — this is the only action that does. MUTATE_FACT requires the target to already exist.
3901
+ - SET_FACT: { targetVar: string, value: string|number|boolean } targetVar must be a
3902
+ registered fact (ACT-032 otherwise). The request does not have to send it: SET_FACT is
3903
+ the only action that can write a key absent from the input facts. MUTATE_FACT requires
3904
+ its target to be present in the input facts.
3895
3905
  - BLOCK: { reason: string } Records a rejection decision. It does NOT halt rule execution —
3896
3906
  subsequent actions and subsequent winning rules still run. Enforcement is the caller's
3897
3907
  responsibility; the decision surfaces as the isBlocked fact.
@@ -3916,7 +3926,7 @@ function registerRuleTools(server, callApi) {
3916
3926
  {
3917
3927
  title: "Update Rule",
3918
3928
  annotations: { readOnlyHint: false, destructiveHint: true },
3919
- description: `Update an existing rule in a DRAFT version. Only provided fields are changed. A new condition tree must stay within ${MAX_CONDITIONS_PER_RULE} conditions (SINGLE nodes) and ${MAX_CONDITION_DEPTH} levels of nesting below the root.`,
3929
+ description: `Update an existing rule in a DRAFT version. Only provided fields are changed. A new condition tree must stay within ${MAX_CONDITIONS_PER_RULE} conditions (SINGLE nodes) and ${MAX_CONDITION_DEPTH} levels of nesting below the root. Saving re-checks every action in the rule, including ones you did not change, and fails with ACT-032 if any action's targetVar is not a registered fact.`,
3920
3930
  inputSchema: z4.object({
3921
3931
  groupId: z4.string().uuid().describe("Policy group ID"),
3922
3932
  versionId: z4.string().uuid().describe("Version ID"),
@@ -4095,7 +4105,7 @@ function registerFactTools(server, callApi) {
4095
4105
  {
4096
4106
  title: "Get Action Runtime Fact Metadata",
4097
4107
  annotations: { readOnlyHint: true },
4098
- 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. Facts are supplied as input or written by a prior action in the same rule; only SET_FACT creates a fact from nothing. Static data, safe to cache in-session.",
4108
+ 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 that can write a key the request did not send, and its targetVar must be a registered fact (ACT-032). Static data, safe to cache in-session.",
4099
4109
  inputSchema: z5.object({})
4100
4110
  },
4101
4111
  async () => callApi("GET", "schema/action-metadata")
@@ -4105,7 +4115,7 @@ function registerFactTools(server, callApi) {
4105
4115
  {
4106
4116
  title: "List Unregistered Facts",
4107
4117
  annotations: { readOnlyHint: true },
4108
- description: "List facts referenced by a version's rules but not yet defined (read-only \u2014 does not block publish/deploy). Version-wide: covers every rule in the version. Each entry carries the inferred type, suggested name, and where it is referenced (condition/action). Register them with lexq_facts_create to enable type validation and the dry-run requirements analyzer.",
4118
+ description: "List facts referenced by a version's rules but not yet defined (read-only). Keys that rules only read do not block publish/deploy; a rule whose action targetVar is not a registered fact is rejected at save and publish with ACT-032. Version-wide: covers every rule in the version. Each entry carries the inferred type, suggested name, and where it is referenced (condition/action). Register them with lexq_facts_create to enable type validation and the dry-run requirements analyzer.",
4109
4119
  inputSchema: z5.object({
4110
4120
  groupId: z5.string().uuid().describe("Policy group ID"),
4111
4121
  versionId: z5.string().uuid().describe("Version ID")
@@ -4138,7 +4148,7 @@ function registerDeployTools(server, callApi) {
4138
4148
  {
4139
4149
  title: "Publish Version",
4140
4150
  annotations: { readOnlyHint: false, destructiveHint: false },
4141
- description: `Publish a DRAFT version (DRAFT \u2192 ACTIVE). Locks the version from further edits. Must have at least one rule. Undefined facts referenced by rules do not block publishing; call lexq_facts_unregistered first to review them. Publishing fails if the version's compiled rules exceed ${MAX_SNAPSHOT_BYTES / 1024} KB, or if its effective end has already passed (P-058); move the end into the future with lexq_versions_update first.`,
4151
+ description: `Publish a DRAFT version (DRAFT \u2192 ACTIVE). Locks the version from further edits. Must have at least one rule. Undefined facts that rules only read do not block publishing; call lexq_facts_unregistered first to review them. Publishing fails if an action's targetVar is not a registered fact (ACT-032), if the version's compiled rules exceed ${MAX_SNAPSHOT_BYTES / 1024} KB, or if its effective end has already passed (P-058); move the end into the future with lexq_versions_update first.`,
4142
4152
  inputSchema: z6.object({
4143
4153
  groupId: z6.string().uuid().describe("Policy group ID"),
4144
4154
  versionId: z6.string().uuid().describe("Version ID to publish"),
@@ -409,7 +409,12 @@ function registerRuleTools(server, callApi) {
409
409
  If a required key is missing, ask the user to confirm the type, isRequired, and description
410
410
  before calling lexq_facts_create — registering facts enables type validation, Console UI
411
411
  autocomplete, and the dry-run requirements analyzer.
412
-
412
+
413
+ An action's targetVar (SET_FACT, MUTATE_FACT) must be a registered fact. Saving or
414
+ publishing a rule whose targetVar is not registered fails with ACT-032, so register it
415
+ with lexq_facts_create first. Keys a rule only reads (condition fields, refVar) may stay
416
+ unregistered.
417
+
413
418
  After saving, lexq_facts_unregistered lists any keys this version references but has not
414
419
  defined (non-blocking, version-wide) — use it to decide what to register.
415
420
 
@@ -438,8 +443,9 @@ function registerRuleTools(server, callApi) {
438
443
 
439
444
  Action parameter schemas:
440
445
  - MUTATE_FACT: { targetVar: string, operator: "ASSIGN"|"ADD"|"SUB"|"MUL"|"DIV", method: "PERCENTAGE"|"AMOUNT", operand: number, refVar?: string, rounding?: RoundingOption }
441
- targetVar is the fact this action reads and writes. It must exist in facts at execution
442
- time as a number — supplied as an input fact or written by a prior action in this rule.
446
+ targetVar is the fact this action reads and writes. It must be a registered fact
447
+ (ACT-032 otherwise), and the request must send it (P-015 otherwise). Its value must be
448
+ a number when the action runs.
443
449
  A missing required fact throws (no 0 default).
444
450
  operand is the arithmetic operand; the unit is dictated by method (percent when
445
451
  PERCENTAGE, absolute amount when AMOUNT). Ranges are not constrained — negative values
@@ -457,8 +463,10 @@ function registerRuleTools(server, callApi) {
457
463
  DIV targetVar /= operand | invalid
458
464
  Constraints: DIV + PERCENTAGE is invalid (use MUL with the inverse). DIV + AMOUNT
459
465
  requires operand !== 0.
460
- - SET_FACT: { targetVar: string, value: string|number|boolean } Creates the fact if absent
461
- — this is the only action that does. MUTATE_FACT requires the target to already exist.
466
+ - SET_FACT: { targetVar: string, value: string|number|boolean } targetVar must be a
467
+ registered fact (ACT-032 otherwise). The request does not have to send it: SET_FACT is
468
+ the only action that can write a key absent from the input facts. MUTATE_FACT requires
469
+ its target to be present in the input facts.
462
470
  - BLOCK: { reason: string } Records a rejection decision. It does NOT halt rule execution —
463
471
  subsequent actions and subsequent winning rules still run. Enforcement is the caller's
464
472
  responsibility; the decision surfaces as the isBlocked fact.
@@ -483,7 +491,7 @@ function registerRuleTools(server, callApi) {
483
491
  {
484
492
  title: "Update Rule",
485
493
  annotations: { readOnlyHint: false, destructiveHint: true },
486
- description: `Update an existing rule in a DRAFT version. Only provided fields are changed. A new condition tree must stay within ${MAX_CONDITIONS_PER_RULE} conditions (SINGLE nodes) and ${MAX_CONDITION_DEPTH} levels of nesting below the root.`,
494
+ description: `Update an existing rule in a DRAFT version. Only provided fields are changed. A new condition tree must stay within ${MAX_CONDITIONS_PER_RULE} conditions (SINGLE nodes) and ${MAX_CONDITION_DEPTH} levels of nesting below the root. Saving re-checks every action in the rule, including ones you did not change, and fails with ACT-032 if any action's targetVar is not a registered fact.`,
487
495
  inputSchema: z4.object({
488
496
  groupId: z4.string().uuid().describe("Policy group ID"),
489
497
  versionId: z4.string().uuid().describe("Version ID"),
@@ -666,7 +674,7 @@ function registerFactTools(server, callApi) {
666
674
  {
667
675
  title: "Get Action Runtime Fact Metadata",
668
676
  annotations: { readOnlyHint: true },
669
- 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. Facts are supplied as input or written by a prior action in the same rule; only SET_FACT creates a fact from nothing. Static data, safe to cache in-session.",
677
+ 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 that can write a key the request did not send, and its targetVar must be a registered fact (ACT-032). Static data, safe to cache in-session.",
670
678
  inputSchema: z5.object({})
671
679
  },
672
680
  async () => callApi("GET", "schema/action-metadata")
@@ -676,7 +684,7 @@ function registerFactTools(server, callApi) {
676
684
  {
677
685
  title: "List Unregistered Facts",
678
686
  annotations: { readOnlyHint: true },
679
- description: "List facts referenced by a version's rules but not yet defined (read-only \u2014 does not block publish/deploy). Version-wide: covers every rule in the version. Each entry carries the inferred type, suggested name, and where it is referenced (condition/action). Register them with lexq_facts_create to enable type validation and the dry-run requirements analyzer.",
687
+ description: "List facts referenced by a version's rules but not yet defined (read-only). Keys that rules only read do not block publish/deploy; a rule whose action targetVar is not a registered fact is rejected at save and publish with ACT-032. Version-wide: covers every rule in the version. Each entry carries the inferred type, suggested name, and where it is referenced (condition/action). Register them with lexq_facts_create to enable type validation and the dry-run requirements analyzer.",
680
688
  inputSchema: z5.object({
681
689
  groupId: z5.string().uuid().describe("Policy group ID"),
682
690
  versionId: z5.string().uuid().describe("Version ID")
@@ -709,7 +717,7 @@ function registerDeployTools(server, callApi) {
709
717
  {
710
718
  title: "Publish Version",
711
719
  annotations: { readOnlyHint: false, destructiveHint: false },
712
- description: `Publish a DRAFT version (DRAFT \u2192 ACTIVE). Locks the version from further edits. Must have at least one rule. Undefined facts referenced by rules do not block publishing; call lexq_facts_unregistered first to review them. Publishing fails if the version's compiled rules exceed ${MAX_SNAPSHOT_BYTES / 1024} KB, or if its effective end has already passed (P-058); move the end into the future with lexq_versions_update first.`,
720
+ description: `Publish a DRAFT version (DRAFT \u2192 ACTIVE). Locks the version from further edits. Must have at least one rule. Undefined facts that rules only read do not block publishing; call lexq_facts_unregistered first to review them. Publishing fails if an action's targetVar is not a registered fact (ACT-032), if the version's compiled rules exceed ${MAX_SNAPSHOT_BYTES / 1024} KB, or if its effective end has already passed (P-058); move the end into the future with lexq_versions_update first.`,
713
721
  inputSchema: z6.object({
714
722
  groupId: z6.string().uuid().describe("Policy group ID"),
715
723
  versionId: z6.string().uuid().describe("Version ID to publish"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexq/cli",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "mcpName": "io.lexq/lexq",
5
5
  "description": "LexQ CLI — manage policies, simulate rules, and deploy from the terminal. Built for humans and AI agents.",
6
6
  "type": "module",
@@ -480,8 +480,10 @@ lexq analytics dry-run --version-id <vid> --debug --json '{
480
480
 
481
481
  **Notes**
482
482
 
483
- - `SET_FACT` creates the fact if it does not exist. `MUTATE_FACT` requires the target to already
484
- be present — that is the division of labor between them.
483
+ - Register a `SET_FACT` target before saving the rule, as the step above does. A rule whose
484
+ `targetVar` is not a registered fact is rejected with `ACT-032`.
485
+ - At execution, `SET_FACT` writes the key even when the request did not send it. `MUTATE_FACT`
486
+ requires the request to send its target. That is the division of labor between them.
485
487
  - Flags appear in `generatedVariables` in the response. `SET_FACT` produces no `__delta` because
486
488
  it is an assignment, not an arithmetic change.
487
489
  - Segment on a `LIST_STRING` fact with `HAS_ANY` / `HAS_ALL` / `HAS_NONE`, not `CONTAINS`.
@@ -181,14 +181,14 @@ Each rule can have multiple actions. Actions fire sequentially.
181
181
  | Type | Description | Key Parameters |
182
182
  |---------------|--------------------------------------------|----------------------------------------------------------------------|
183
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` |
184
+ | `SET_FACT` | Assign a literal value to a registered fact | `targetVar`, `value` |
185
185
  | `BLOCK` | Record a rejection decision | `reason` |
186
186
 
187
187
  ### `MUTATE_FACT` parameters
188
188
 
189
189
  | Parameter | Required | Meaning |
190
190
  |-------------|----------|-------------------------------------------------------------------------------|
191
- | `targetVar` | always | The fact this action **reads and writes**. Must already exist as a number. |
191
+ | `targetVar` | always | The fact this action **reads and writes**. Must be registered and present as a number at execution. |
192
192
  | `operator` | always | `ASSIGN` \| `ADD` \| `SUB` \| `MUL` \| `DIV` |
193
193
  | `method` | always | `PERCENTAGE` \| `AMOUNT` — dictates the unit of `operand` |
194
194
  | `operand` | always | The arithmetic operand. Percent when PERCENTAGE, absolute amount when AMOUNT. |
@@ -235,8 +235,15 @@ Use `refVar` when the base differs from the target:
235
235
 
236
236
  ### `SET_FACT` vs `MUTATE_FACT`
237
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.
238
+ Both actions write to `targetVar`, and it must be a **registered fact**. Saving or publishing a
239
+ rule whose `targetVar` is not registered fails with `ACT-032`; register it with
240
+ `lexq facts create` first. Keys a rule only reads (condition fields, `refVar`) may stay
241
+ unregistered.
242
+
243
+ At execution, they differ in what the request must send. `SET_FACT` writes the value even when
244
+ the request did not send the key. `MUTATE_FACT` requires the request to send the target (`P-015`
245
+ otherwise), and the target's value must be a number when the action runs. "Write something the
246
+ request didn't send" is `SET_FACT`'s job.
240
247
 
241
248
  ### `BLOCK` does not halt execution
242
249