@stalfh233/omc-cli 0.5.10 → 0.5.11

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.
@@ -1491,6 +1491,32 @@ export function validateRuleNodeGraph(graph, ruleCode, schemaCode, options = {})
1491
1491
  const relaxEnums = options.relaxEnums === true;
1492
1492
  if (nodeRecords.length !== nodes.length)
1493
1493
  blockers.push({ code: "rule-graph-node-not-object", message: "nodes 中存在非对象元素" });
1494
+ // r42 头号返工根因(维护者同踩):filterCondition 的目标查找条件键是
1495
+ // mainConditions(FilterCondition 模型,List<List<TableCondition>>),不是
1496
+ // 触发条件/BRANCH 出口的 conditionGroups——错键被平台静默反序列化为空,
1497
+ // 引擎零循环恒报「查找范围不存在数据」,形似"跨模型 UPDATE 不可用"(曾据
1498
+ // 此误判平台边界,反编译 FilterCondition.mainConditions + mainConditions 正形
1499
+ // 真机回写成功双重实证后纠正)。fail closed:错键当场拒绝。
1500
+ for (const node of nodeRecords) {
1501
+ const nodeType = String(node.nodeType ?? "");
1502
+ if (nodeType !== "UPDATE" && nodeType !== "DELETE" && nodeType !== "CREATE" && nodeType !== "ASSIGN" && nodeType !== "QUERY")
1503
+ continue;
1504
+ const fc = node.filterCondition;
1505
+ if (fc === undefined || fc === null || typeof fc !== "object" || Array.isArray(fc))
1506
+ continue;
1507
+ const record = fc;
1508
+ if ("mainConditions" in record)
1509
+ continue;
1510
+ const wrongKeys = ["conditionGroups", "conditions", "mainTableConditions", "filterGroups", "targetConditionGroups"].filter((key) => key in record);
1511
+ if (wrongKeys.length > 0 || Object.keys(record).length === 0) {
1512
+ blockers.push({
1513
+ code: "rule-graph-filter-condition-wrong-key",
1514
+ nodeCode: String(node.nodeCode ?? ""),
1515
+ key: "filterCondition",
1516
+ message: `${nodeType} "${String(node.nodeCode ?? "")}" 的 filterCondition 键写错(${wrongKeys.join("、") || "空对象"})——目标查找条件用 mainConditions: [[{targetSchemaDataItem, ruleConditionType, ruleValueType, value|currentSchemaDataItem}]];conditionGroups 是触发条件/BRANCH 出口的键,放这里会被平台静默忽略 → 引擎恒报「查找范围不存在数据」(形似跨模型回写不可用)。形状见 omc describe rule.save --example business-rule-branch-conditional`,
1517
+ });
1518
+ }
1519
+ }
1494
1520
  // Cross-model write-back: SUPPORTED (verified live 2026-09-28). An UPDATE whose
1495
1521
  // `targetObjectCode` is a DIFFERENT model than the rule's own model writes back
1496
1522
  // correctly once TWO prerequisites hold — a 2026-09-27 probe that reported
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stalfh233/omc-cli",
3
- "version": "0.5.10",
3
+ "version": "0.5.11",
4
4
  "description": "CloudPivot 8.6 configuration capability CLI — governed, fail-closed, coverage-manifest bounded.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -52,9 +52,9 @@
52
52
  "access": "public"
53
53
  },
54
54
  "dependencies": {
55
- "@stalfh233/omc-fake-platform": "0.5.10",
55
+ "@stalfh233/omc-fake-platform": "0.5.11",
56
56
  "commander": "14.0.3",
57
- "omc-core": "0.5.10",
57
+ "omc-core": "0.5.11",
58
58
  "proper-lockfile": "4.1.2",
59
59
  "write-file-atomic": "6.0.0",
60
60
  "zod": "^3.23.8",
@@ -122,6 +122,7 @@ rules:
122
122
 
123
123
  - **每个 filter 项必须有且只有一个条件来源**:`from`(动态 EQ)或一个比较键(`equals`/`notEquals`/`gt`/`gte`/`lt`/`lte` + 标量)。缺来源 `intent-rule-leaf-source-missing` 拒绝;**绝不**静默成 `EQ null`。
124
124
  - 动作节点的条件分「定位数据」与「执行门」两类,**别混**(详见下「规则图的触发条件」)。
125
+ - **跨模型 UPDATE 目标查找键=`filterCondition.mainConditions`**(`[[{targetSchemaDataItem, ruleConditionType, ruleValueType, value|currentSchemaDataItem}]]`,非触发条件的 conditionGroups——错键静默反序列化为空,引擎恒报「查找范围不存在数据」形似跨模型不可用,r42 曾误判;校验 `rule-graph-filter-condition-wrong-key` 已拦)。连坑:叶取值键 `value` 非 fixedValue;`rule.node.update` 只写 DRAFT,改完须 `rule.enable`/`--publish` 重发布才生效。
125
126
  - **跨模型写(`targetObjectCode`≠规则模型)平台支持、可运行时生效**(2026-09-28 真机复核)。两个前提:① 承载它的规则必须真的触发——`Create` 规则在提交时触发;`Update` 规则只在 `data.update` 触发,**submit 不执行它**(放进 `Update` 是典型静默空转,lint 警告 `rule-graph-cross-model-update-trigger-inert`;也可绑定流程事件如 `end`)。② 目标行必须已提交——目标查询不匹配 DRAFT 行,`data.save` 未 submit 的行不回写。
126
127
  - 关联字段:`type: WORK_SHEET` + `relativeCode: <目标模型>` + `options.displayField`,与 `field.create` 行形状一致。(键名是 `relativeCode`,wire 键 `relativeSchemaCode`,别混。)
127
128
  - 节点显示名用 activity 级的 `name`(`participant.name` 只作参与者说明,平台不认作节点名;`{type: Originator, name: 部门负责人}` 会被工具提升为节点名)。
@@ -55,7 +55,7 @@ omc help omc-write-hazards
55
55
  - **BIZ_ACTION 判成功只看传输**:REST 适配器解析响应后直接返回,**不校验 `errcode`**。扩展接口回 `{"errcode":50000}` + HTTP 200 会被当成节点成功(日志 `biz action node execute successful`)。要阻断必须走表单 `onValidate` 或数据规则,不能靠业务返回码。
56
56
  - **`rule.run`/自定义规则不回写出参**(r26 实证 2 轮):出参合并只发生在预置 Update 规则的执行上下文;`rule.run` 手动触发与自定义规则不把服务出参写回本模型——出参落表要走「BIZ_ACTION 节点 outputMappings + 数据事件触发」,验收用 data.load 看字段而非 rule.run 回执。
57
57
  - **出参回写三前提(r28b 8 组实验定案,单点总纲)**:① 响应 JSON 根级平铺出参键 ② 预置 Create/Update 规则上下文 ③ data.submit/data.update 触发(data.save 不触发)。三者缺一出参恒 null 且节点日志仍 successful——外部接口回信封的(`{code,message,data:[...]}`),先落平铺整形端点(平台扩展)再配 outputMappings,不要反复换规则形状试。
58
- - **布尔出参映射到文本字段 → ClassCastException 50000**(r28b 实证):服务出参 `bizPropertyType:LOGICAL` 的值映射到 SHORT_TEXT 字段会让规则执行炸 50000——布尔出参只能映射 LOGICAL 字段;要落文本先在扩展侧转字符串。
58
+ - **布尔出参映射到文本字段 → ClassCastException 50000**(r28b):LOGICAL 出参映射 SHORT_TEXT 即炸——布尔只映射 LOGICAL 字段,落文本先在扩展侧转字符串。
59
59
  - **审批提交的 formData 带子表数组 = 追加行**(r28b 实证):approval submit 的 formData 里带子表数组会被平台当「追加行」处理,审批回执只回传主表字段——审批链路里要改子表行,用 data.update 单独写,不要塞进 formData。
60
60
  - **workItemId 不在 instanceActivity 里**(r28b 实证):流程实例活动查询不返回 workItemId;办理待办要的 workItemId 从 `search_workitems?state=PENDING` 的 `content[].id` 取。
61
61
  - **模型创建/删除非原子,会有半态残留**(r28b 实证 ~20min):model.create 在表单层撞错(如「表单已存在」)时 schema 可能已半落库——refused 后换名重试前先 model.list 核对半态并清理;同理模型删除后平台读面不可见但库里可能留僵尸行(引擎报 `appFunction not exist` 就是它在作祟),迁移/复用编码前先核对。
@@ -193,13 +193,15 @@ omc call field.publish --env local --args '{"schemaCode":"expense"}'
193
193
  - **`transferDepartment` 迁人不迁作用域**(r33 真机):换部门后 `role.userScope` 仍指旧部门——迁移后复核成员作用域。
194
194
  - **`user.delete` 是软删**(r33 真机):回 `deleted:true` 但 `user.info` 仍 `exists:true`(DISABLE)——验证口径用列表/状态,别称物理清除。
195
195
  - **「名称重复 200001」≠ 失败**(r33 真机):多为首次已建成、重发才撞重复——先读回确认首建结果再决定。
196
- - **删了的东西≠删干净(孤儿三连,1101 三例)**:①删模型留收藏+h_biz_* 行→日志刷 `appFunction not exist`;②规则死服务 A1→submit 500015;③流程模板删后绑定残留(h_workflow_relative_object/header 指死 code)→getWorkflow 50000。都是删上游留下游引用、报错在别处——先查孤儿引用,维护者按表清。
197
- - **两套条件 DSL(r38/r39)**:listview.configure `conditions`={propertyCode, filterType, **defaultValue**}(值键叫 defaultValue);data.list `filter`={op, field, value}。互抄必错——形状各查 `--param conditions`/`--param filter`。
198
- - **表单读回以控件清单为准,不看布尔位(r40)**:form.get 的 `published` 布尔会 false→true 抖动;draftViewJson 可含已删字段悬空引用(rebuild 自清)。判定布局依据=`publishedControlCodes` 内容;configure_form 回执已点名 `missingFieldCodes`。
199
- - **submit 被拒仍可能已落草稿(r40)**:`data.save --submit:true` 遇许可证/权限拒绝时平台可能在拒答前已写草稿——拒后 data.list 对账 total,残留 data.delete 单清。
200
- - **空聚合≠模型存在(r40)**:rule.list/datarule.list 对不存在模型静默回空——「0 条规则」≠模型在(mcc_contract 从不存在却一路答空)。rule.list 已修(空时探真身标 `modelPresent:false`);datarule.list 同陷阱——判存在性一律 model.inspect。
201
- - **form.publish(rebuild) 后立即 submit 可能丢字段(r41 疑似竞态)**:链内演示行 `order_no` 落 null,同形状延迟复现正常。落演示行后 `data.load` 抽验非选项字段,缺值 data.save 单补,不重跑整链。
196
+ - **删了的东西≠删干净(孤儿三连,1101 三例)**:①删模型留收藏/h_biz_* 行→日志 appFunction not exist;②规则死服务 A1→submit 500015;③流程模板删后绑定残留→getWorkflow 50000。都是报错在别处——先查孤儿引用。
197
+ - **两套条件 DSL(r38/r39)**:listview `conditions`={propertyCode, filterType, defaultValue};data.list `filter`={op, field, value}。互抄必错。
198
+ - **表单读回以控件清单为准(r40)**:`published` 布尔会抖动、draftViewJson 可含悬空引用(rebuild 自清)——判定依据=publishedControlCodes 内容;configure_form 回执已点名 missingFieldCodes。
199
+ - **submit 被拒仍可能已落草稿(r40)**:许可证/权限拒绝可能拒答前已写草稿——拒后对账 total,残留单清。
200
+ - **空聚合≠模型存在(r40)**:rule.list 对不存在模型静默回空(已修,空时标 modelPresent:false);datarule.list 响亮拒 601003。判存在性用 model.inspect。
201
+ - **form.publish(rebuild) 后立即 submit 可能丢字段(r41 疑似竞态)**:链内演示行 order_no 落 null,延迟复现正常。落行后 data.load 抽验,缺值单补。
202
202
  - **data.list 选项列投影可为 null(r40/r41)**:`all:true`/queryCode 下 RADIO 读 null,`data.load`/`filter` 才有值——验证选项字段以 data.load 为权威。
203
+ - **流程绑定行不可 data.save 直改(r42)**:COMPLETED 行直改打回 PROCESSING、值不落、可能岔行——走提交流程。连续 submit 撞限流 100005——批量先 workitem.list 取 workItemId。
204
+ - **带流程模型 data.submit 必停审批位(r43)**:批量初始化滞留待办——流程加条件分支按单据类型直达结束。SEQNO 不回收。
203
205
  - **读回形状≠可写形状**(r38):`listview.get` 读回条件带 `null` 字段,原样回写被拒——读回是输出形态,可写面有自己的契约;null 归一(false/省略)或只回写要改的键。
204
206
  - **data.list 的 columns 收窄可能静默空**(r38):非视图列字段投影 null;甚至 columns+分页 total>0 而 items 0——判"无数据"先去 columns 复查或用 data.load。
205
207