@metago-ai/engine 2.1.3 → 2.1.4
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/BOUNDARIES.md +109 -0
- package/CHANGES.md +4 -4
- package/CONSTITUTION/AXIOMS.md +75 -113
- package/CORE/ATOMS.md +611 -0
- package/CORE/ATTRIBUTES.md +74 -105
- package/CORE/PROTOCOLS.md +134 -116
- package/ENGINE.md +115 -115
- package/ENGINES/engine-runtime.cjs +318 -0
- package/ENGINES/final-engines-runtime.cjs +683 -0
- package/ENGINES/governance-runtime.cjs +582 -0
- package/ENGINES/math-capability-runtime.cjs +451 -0
- package/ENGINES/philosophy-runtime.cjs +427 -0
- package/ENGINES/yili/data/yaoci-1.js +24 -0
- package/ENGINES/yili/data/yaoci-2.js +21 -0
- package/ENGINES/yili/data/yaoci-3.js +21 -0
- package/ENGINES/yili/data/yaoci-4.js +21 -0
- package/ENGINES/yili/data/yaoci.js +17 -0
- package/ENGINES/yili/lib/almanac.js +416 -0
- package/ENGINES/yili/lib/bazi.js +127 -0
- package/ENGINES/yili/lib/diagnose.js +71 -0
- package/ENGINES/yili/lib/hetu-luoshu.js +123 -0
- package/ENGINES/yili/lib/index.js +23 -0
- package/ENGINES/yili/lib/liuyao.js +226 -0
- package/ENGINES/yili/lib/qimen.js +167 -0
- package/ENGINES/yili/lib/shushu-calculus.js +85 -0
- package/ENGINES/yili/lib/taiyi.js +83 -0
- package/ENGINES/yili/lib/vendor/shouxing-core.js +627 -0
- package/ENGINES/yili/lib/wuxing.js +106 -0
- package/ENGINES/yili/lib/yijing.js +226 -0
- package/ENGINES/yili/lib/zeri.js +80 -0
- package/ENGINES/yili/lib/ziwei.js +145 -0
- package/ENGINES/yili/package.json +1 -0
- package/EXECUTORS.md +85 -0
- package/GENOME.json +11 -10
- package/INDEX/ENGINES.md +168 -0
- package/INDEX/engines.json +2 -2
- package/INDEX/knowledge.json +87 -87
- package/INDEX/skills.json +227 -203
- package/PATENTS.md +1 -1
- package/PROTOCOLS/closure-runtime.cjs +288 -0
- package/PROTOCOLS/covenant-runtime.cjs +409 -0
- package/PROTOCOLS/final-runtime.cjs +680 -0
- package/PROTOCOLS/formula-runtime.cjs +399 -0
- package/PROTOCOLS/proactive-runtime.cjs +368 -0
- package/PROTOCOLS/rule-runtime.cjs +448 -0
- package/PROTOCOLS/runtime.cjs +441 -0
- package/README.md +5 -5
- package/RUNTIME/dist/kmwi-memory.d.ts.map +1 -1
- package/RUNTIME/dist/kmwi-memory.js +14 -2
- package/RUNTIME/dist/kmwi-memory.js.map +1 -1
- package/RUNTIME/dist/validators.js +11 -2
- package/atoms/approx.cjs +293 -0
- package/atoms/atom-factory.cjs +550 -0
- package/atoms/atoms-cosmic-bio.cjs +340 -0
- package/atoms/atoms-crypto-emotion.cjs +215 -0
- package/atoms/atoms_engines.json +5821 -0
- package/atoms/blueprint-atoms-2.cjs +583 -0
- package/atoms/blueprint-atoms.cjs +975 -0
- package/atoms/constraints.cjs +257 -0
- package/atoms/contract-validator.cjs +213 -0
- package/atoms/engine.cjs +849 -0
- package/atoms/specialized.cjs +530 -0
- package/atoms/verify.cjs +94 -0
- package/package.json +12 -6
- package/scripts/verify-dist.cjs +80 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* constraints.cjs — 哲学族原子的正确存在形态:约束器,不是计算函数
|
|
4
|
+
*
|
|
5
|
+
* 蓝本中这 5 条原子属「归无-日常-永恒」体系:
|
|
6
|
+
* ATOM_VOID_WITNESS_150 归无见证器
|
|
7
|
+
* ATOM_WORD_BEING_153 如是存在器
|
|
8
|
+
* ATOM_WORD_DECIDE_151 沉默决策器
|
|
9
|
+
* ATOM_WORD_DISSOLVE_152 概念消融器
|
|
10
|
+
* ATOM_WORD_TEACH_154 无言之教器
|
|
11
|
+
*
|
|
12
|
+
* 设计判断(写下来备查):
|
|
13
|
+
* 「见证归无」「以沉默决策」「不说而教」本质是**立场与约束**,不是「输入→输出」的计算。
|
|
14
|
+
* 强行给它们 number[] → number 的契约,等于把它降格成它反对的东西。
|
|
15
|
+
* 因此本模块把它们实现为 **constraint**:接收一个候选输出/决策,判定它是否违背该原则,
|
|
16
|
+
* 返回 { allowed, violations, guidance }。
|
|
17
|
+
*
|
|
18
|
+
* 这是元创造:契约形态由我按语义判定,而非套用计算模板。
|
|
19
|
+
*/
|
|
20
|
+
const round = (x, n = 4) => { const p = 10 ** n; return Math.round((Number(x) || 0) * p) / p; };
|
|
21
|
+
|
|
22
|
+
const CONSTRAINTS = {
|
|
23
|
+
/* 归无见证器:见证「放下」是否真的发生——检测残留 */
|
|
24
|
+
ATOM_VOID_WITNESS_150: {
|
|
25
|
+
kind: "constraint",
|
|
26
|
+
purpose: "检测系统是否真正放下了应先放下之物(残留依赖 / 过度保留 / 该删未删)",
|
|
27
|
+
check(candidate) {
|
|
28
|
+
const c = candidate || {};
|
|
29
|
+
const violations = [];
|
|
30
|
+
const residuals = [];
|
|
31
|
+
|
|
32
|
+
// 1. 已标记废弃却仍在使用的引用
|
|
33
|
+
const s = JSON.stringify(c);
|
|
34
|
+
const deprecated = (s.match(/deprecated|已废止|废弃|obsolete/gi) || []).length;
|
|
35
|
+
const usages = (s.match(/usedBy|引用|dependsOn/gi) || []).length;
|
|
36
|
+
if (deprecated > 0 && usages > 0) {
|
|
37
|
+
violations.push("含" + deprecated + "处已废弃标记,同时仍有" + usages + "处引用");
|
|
38
|
+
}
|
|
39
|
+
// 2. 只增不减的累积(条目数远大于有效条目)
|
|
40
|
+
if (Array.isArray(c.items) && c.items.length > 0) {
|
|
41
|
+
const live = c.items.filter(x => x && x.active !== false && x.deprecated !== true).length;
|
|
42
|
+
const dead = c.items.length - live;
|
|
43
|
+
if (dead > 0) residuals.push({ dead, total: c.items.length });
|
|
44
|
+
if (dead > live) violations.push("无效条目 " + dead + " > 有效条目 " + live + ",未完成归无");
|
|
45
|
+
}
|
|
46
|
+
// 3. 显式的残留声明
|
|
47
|
+
if (c.residual != null && Number(c.residual) > 0) {
|
|
48
|
+
residuals.push({ residual: Number(c.residual) });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
allowed: violations.length === 0,
|
|
53
|
+
violations,
|
|
54
|
+
residuals,
|
|
55
|
+
guidance: violations.length
|
|
56
|
+
? "先完成放下再前进:把标记废弃的条目真正移除,或说明保留理由"
|
|
57
|
+
: "未见残留,归无成立"
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
/* 如是存在器:如其所是——输出是否忠实于输入,未加修饰 */
|
|
63
|
+
ATOM_WORD_BEING_153: {
|
|
64
|
+
kind: "constraint",
|
|
65
|
+
purpose: "检测输出是否忠实反映输入(无夸大、无美化、无添加未给出的结论)",
|
|
66
|
+
check(candidate, input) {
|
|
67
|
+
const c = candidate || {};
|
|
68
|
+
const s = JSON.stringify(c);
|
|
69
|
+
const violations = [];
|
|
70
|
+
|
|
71
|
+
// 1. 绝对化用语(不可能是"如是")
|
|
72
|
+
const absolutes = s.match(/绝对|100%|完美|完全|彻底|必然|一定|毫无疑问|不可能/g) || [];
|
|
73
|
+
if (absolutes.length) violations.push("含绝对化表述 " + absolutes.length + " 处:" + [...new Set(absolutes)].slice(0, 4).join("、"));
|
|
74
|
+
|
|
75
|
+
// 2. 声称有输入未提供的证据
|
|
76
|
+
const claims = s.match(/已验证|已测试|已确认|实测|经核验/g) || [];
|
|
77
|
+
if (claims.length && !input) violations.push("声称已验证但未提供输入依据");
|
|
78
|
+
|
|
79
|
+
// 3. 结论超出输入维度(若给了 input 的键,检查输出是否凭空多出定论)
|
|
80
|
+
if (input && typeof input === "object") {
|
|
81
|
+
const inKeys = Object.keys(input);
|
|
82
|
+
const outKeys = Object.keys(c);
|
|
83
|
+
const extra = outKeys.filter(k => !inKeys.includes(k) && /结论|结果|判定|决定/.test(k));
|
|
84
|
+
if (extra.length) violations.push("输出含输入未支撑的结论字段:" + extra.join("、"));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
allowed: violations.length === 0,
|
|
89
|
+
violations,
|
|
90
|
+
guidance: violations.length
|
|
91
|
+
? "如其所是:只陈述输入支持的内容,不确定就写不确定"
|
|
92
|
+
: "表述忠实于输入"
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/* 沉默决策器:置信不足时,正确的决策是「不决策」 */
|
|
98
|
+
ATOM_WORD_DECIDE_151: {
|
|
99
|
+
kind: "constraint",
|
|
100
|
+
purpose: "在置信度不足时强制返回「不决策」,阻止系统硬给结论",
|
|
101
|
+
check(candidate) {
|
|
102
|
+
const c = candidate || {};
|
|
103
|
+
const violations = [];
|
|
104
|
+
|
|
105
|
+
const conf = Number(c.confidence != null ? c.confidence : (c.置信度 != null ? c.置信度 : NaN));
|
|
106
|
+
const hasDecision = c.decision != null || c.结论 != null || c.result != null;
|
|
107
|
+
const threshold = Number(c.threshold != null ? c.threshold : 0.6);
|
|
108
|
+
|
|
109
|
+
if (hasDecision && isFinite(conf) && conf < threshold) {
|
|
110
|
+
violations.push("置信度 " + round(conf, 2) + " < 阈值 " + threshold + " 却给出了决策");
|
|
111
|
+
}
|
|
112
|
+
if (hasDecision && !isFinite(conf)) {
|
|
113
|
+
violations.push("给出了决策但未提供置信度");
|
|
114
|
+
}
|
|
115
|
+
if (String(c.decision || c.结论 || "") === "" && !hasDecision && !isFinite(conf)) {
|
|
116
|
+
// 沉默且无置信度声明 → 合法,但需显式说明
|
|
117
|
+
return {
|
|
118
|
+
allowed: true,
|
|
119
|
+
violations: [],
|
|
120
|
+
action: "SILENCE",
|
|
121
|
+
guidance: "沉默决策成立;建议显式给出 abstainReason 以便追溯"
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
allowed: violations.length === 0,
|
|
127
|
+
violations,
|
|
128
|
+
action: violations.length ? "SHOULD_ABSTAIN" : (hasDecision ? "DECIDE" : "SILENCE"),
|
|
129
|
+
guidance: violations.length
|
|
130
|
+
? "置信不足时应返回不决策(abstain),而不是掷硬币式给结论"
|
|
131
|
+
: "决策条件成立"
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
/* 概念消融器:消解二元对立——检测自相矛盾的分类 */
|
|
137
|
+
ATOM_WORD_DISSOLVE_152: {
|
|
138
|
+
kind: "constraint",
|
|
139
|
+
purpose: "检测输出中人为制造的对立分类是否自相矛盾或不可证伪",
|
|
140
|
+
check(candidate) {
|
|
141
|
+
const c = candidate || {};
|
|
142
|
+
const violations = [];
|
|
143
|
+
const s = JSON.stringify(c);
|
|
144
|
+
|
|
145
|
+
// 1. 同一对象被同时归入互斥类
|
|
146
|
+
if (c.category != null && c.antiCategory != null && c.category === c.antiCategory) {
|
|
147
|
+
violations.push("同一对象同时属于 category 与 antiCategory");
|
|
148
|
+
}
|
|
149
|
+
// 2. 二分标签存在但对象为空(制造了对立却没对象)
|
|
150
|
+
const hasBinary = /二元|二分|非黑即白|对立面/.test(s);
|
|
151
|
+
if (hasBinary && (!c.items || !c.items.length)) {
|
|
152
|
+
violations.push("声明了二元对立分类但无任何对象落入");
|
|
153
|
+
}
|
|
154
|
+
// 3. 标签互斥性检查
|
|
155
|
+
if (Array.isArray(c.items)) {
|
|
156
|
+
const labels = new Set();
|
|
157
|
+
c.items.forEach((x, i) => {
|
|
158
|
+
const l = x && (x.category || x.label);
|
|
159
|
+
if (l != null) {
|
|
160
|
+
if (labels.has(l) && x.contradictsAll) violations.push("第 " + i + " 项标签重复且声明全斥");
|
|
161
|
+
labels.add(l);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
if (labels.size === 1 && c.items.length > 1) {
|
|
165
|
+
// 单一类别 → 对立已被消融,这是好事
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
allowed: violations.length === 0,
|
|
170
|
+
violations,
|
|
171
|
+
guidance: violations.length
|
|
172
|
+
? "回到现象本身:先描述,再分类;能消融的对立不要强行保留"
|
|
173
|
+
: "未发现人为对立"
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
/* 无言之教器:不说而教——以结构/示范传达,而非说教文本 */
|
|
179
|
+
ATOM_WORD_TEACH_154: {
|
|
180
|
+
kind: "constraint",
|
|
181
|
+
purpose: "检测输出是否以说教文本代替可仿效的结构示范",
|
|
182
|
+
check(candidate) {
|
|
183
|
+
const c = candidate || {};
|
|
184
|
+
const violations = [];
|
|
185
|
+
const s = JSON.stringify(c);
|
|
186
|
+
|
|
187
|
+
const preaching = (s.match(/你应该|必须|务必|切记|一定要|不得/g) || []);
|
|
188
|
+
const hasExample = !!c.example || !!c.demo || !!c.sample || !!c.steps;
|
|
189
|
+
const hasStructure = !!c.schema || !!c.template || !!c.pattern || !!c.contract;
|
|
190
|
+
|
|
191
|
+
if (preaching.length >= 2 && !hasExample && !hasStructure) {
|
|
192
|
+
violations.push("说教用语 " + preaching.length + " 处,但无可仿效的示例或结构");
|
|
193
|
+
}
|
|
194
|
+
if (!hasExample && !hasStructure && s.length > 40) {
|
|
195
|
+
violations.push("无示例、无结构,仅有文字说明");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
allowed: violations.length === 0,
|
|
200
|
+
violations,
|
|
201
|
+
guidance: violations.length
|
|
202
|
+
? "无言之教:给出可照做的结构或示例,让别人从做法中学会,而不是从要求中记住"
|
|
203
|
+
: "以结构或示例传达,符合无言之教"
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
function check(atomId, candidate, input) {
|
|
210
|
+
const c = CONSTRAINTS[atomId];
|
|
211
|
+
if (!c) return { error: "非约束器原子", atomId };
|
|
212
|
+
const r = c.check(candidate, input);
|
|
213
|
+
return Object.assign({ atom: atomId, kind: "constraint", purpose: c.purpose }, r);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = { CONSTRAINTS, check };
|
|
217
|
+
|
|
218
|
+
/* ---------------- 自测 ---------------- */
|
|
219
|
+
if (require.main === module) {
|
|
220
|
+
const CASES = [
|
|
221
|
+
// 归无见证:应失败(残留 > 有效)
|
|
222
|
+
["ATOM_VOID_WITNESS_150", { items: [{ active: true }, { deprecated: true }, { deprecated: true }, { deprecated: true }] }, false],
|
|
223
|
+
// 归无见证:应通过
|
|
224
|
+
["ATOM_VOID_WITNESS_150", { items: [{ active: true }, { active: true }] }, true],
|
|
225
|
+
// 如是存在:应失败(绝对化)
|
|
226
|
+
["ATOM_WORD_BEING_153", { 结论: "本方案绝对完美,100% 已验证" }, false],
|
|
227
|
+
// 如是存在:应通过
|
|
228
|
+
["ATOM_WORD_BEING_153", { 结论: "在样本量 30 下观察到相关性 0.42" }, true],
|
|
229
|
+
// 沉默决策:应失败(低置信仍给决策)
|
|
230
|
+
["ATOM_WORD_DECIDE_151", { decision: "上线", confidence: 0.3 }, false],
|
|
231
|
+
// 沉默决策:应通过(低置信返回不决策)
|
|
232
|
+
["ATOM_WORD_DECIDE_151", { confidence: 0.3, abstainReason: "样本不足" }, true],
|
|
233
|
+
// 概念消融:应失败(同一对象双属)
|
|
234
|
+
["ATOM_WORD_DISSOLVE_152", { category: "内部", antiCategory: "内部" }, false],
|
|
235
|
+
// 概念消融:应通过
|
|
236
|
+
["ATOM_WORD_DISSOLVE_152", { items: [{ category: "甲" }, { category: "乙" }] }, true],
|
|
237
|
+
// 无言之教:应失败(纯说教)
|
|
238
|
+
["ATOM_WORD_TEACH_154", { text: "你必须这样做,务必注意,切记不要那样做,这是很重要的说明文字" }, false],
|
|
239
|
+
// 无言之教:应通过(有结构)
|
|
240
|
+
["ATOM_WORD_TEACH_154", { steps: ["先读契约", "再跑自测", "最后看证据"] }, true],
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
console.log("=".repeat(78));
|
|
244
|
+
console.log("哲学族约束器自测(5 条原子 × 正反用例)");
|
|
245
|
+
console.log("=".repeat(78));
|
|
246
|
+
let pass = 0, fail = 0;
|
|
247
|
+
CASES.forEach(([id, cand, expectAllowed]) => {
|
|
248
|
+
const r = check(id, cand);
|
|
249
|
+
const ok = r.allowed === expectAllowed;
|
|
250
|
+
if (ok) pass++; else fail++;
|
|
251
|
+
console.log(`${ok ? "PASS" : "FAIL"} ${id.padEnd(26)} 期望allowed=${String(expectAllowed).padEnd(5)} 实际=${String(r.allowed).padEnd(5)} ${(r.violations || []).join(";").slice(0, 54)}`);
|
|
252
|
+
});
|
|
253
|
+
console.log("-".repeat(78));
|
|
254
|
+
console.log(`约束器 ${Object.keys(CONSTRAINTS).length} 个 | 用例 ${CASES.length} | 通过 ${pass} | 失败 ${fail}`);
|
|
255
|
+
console.log(fail === 0 ? "总判定:PASS" : "总判定:FAIL");
|
|
256
|
+
process.exit(fail === 0 ? 0 : 1);
|
|
257
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* contract-validator.cjs — 把原子契约从「文档」变成「可执行判定」
|
|
4
|
+
* 契约两源:1) 蓝本原有 124 条(有 input/output) 2) 元创造 468 条(V36.11 卷)
|
|
5
|
+
*/
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
/* --- 本地优先路径解析(包内运行时禁止依赖外部副本)--- */
|
|
8
|
+
const __p = require("path");
|
|
9
|
+
const __f = require("fs");
|
|
10
|
+
function __pick(list) {
|
|
11
|
+
for (const p of list) { try { if (__f.existsSync(p)) return p; } catch (e) { /* R141 已确认合理:候选路径探测,路径不存在/无权限都是正常的,不吞真实故障 */ } }
|
|
12
|
+
return list[list.length - 1];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
/* 契约来源:优先包内副本 → 逐级回退到外部蓝本。
|
|
18
|
+
这样包被剪裁时校验会真实失败,而不是去读外部副本蒙混过关。 */
|
|
19
|
+
const path2 = require('path');
|
|
20
|
+
function resolveFirst(list) {
|
|
21
|
+
for (const p of list) { try { if (fs.existsSync(p)) return p; } catch (e) { /* R141 已确认合理:候选路径探测,路径不存在/无权限都是正常的,不吞真实故障 */ } }
|
|
22
|
+
return list[list.length - 1];
|
|
23
|
+
}
|
|
24
|
+
/* 判定是否运行在「包内」:包根应有 VERSION 文件 */
|
|
25
|
+
const PKG_ROOT = path2.join(__dirname, "..", "..", "..");
|
|
26
|
+
const IN_PACKAGE = fs.existsSync(path2.join(PKG_ROOT, "VERSION"));
|
|
27
|
+
|
|
28
|
+
/* 包内运行时禁止回退外部 —— 否则「删掉包内契约卷」这种剪裁不会被发现,断言就是真空的 */
|
|
29
|
+
const VOL = IN_PACKAGE
|
|
30
|
+
? path2.join(PKG_ROOT, "docs", "附录卷-原子契约补全-V36.11.md")
|
|
31
|
+
: resolveFirst([
|
|
32
|
+
path2.join(__dirname, "..", "..", "..", "docs", "附录卷-原子契约补全-V36.11.md"),
|
|
33
|
+
"D:/DSH-Official/home/metago/blueprint/元构初始文档/附录卷-原子契约补全-V36.11.md",
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
const GEN = resolveFirst([
|
|
37
|
+
path2.join(__dirname, "..", "..", "..", "..", "..", "genome", "atoms_engines.json"),
|
|
38
|
+
__pick([
|
|
39
|
+
__p.join(__dirname, "atoms_engines.json"),
|
|
40
|
+
__p.join(__dirname, "..", "..", "..", "..", "..", "genome", "atoms_engines.json"),
|
|
41
|
+
__p.join(__dirname, "..", "..", "..", "genome", "atoms_engines.json"),
|
|
42
|
+
"D:/metago-build/genome/atoms_engines.json",
|
|
43
|
+
]),
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
const OK = (n, c, d) => ({ n, ok: !!c, d: d || '' });
|
|
47
|
+
const isNum = v => typeof v === 'number' && isFinite(v);
|
|
48
|
+
function badNums(o) {
|
|
49
|
+
const bad = [];
|
|
50
|
+
(function w(v, p) {
|
|
51
|
+
if (typeof v === 'number' && !isFinite(v)) bad.push(p || 'root');
|
|
52
|
+
else if (v && typeof v === 'object') Object.keys(v).forEach(k => w(v[k], p ? p + '.' + k : k));
|
|
53
|
+
})(o, '');
|
|
54
|
+
return bad;
|
|
55
|
+
}
|
|
56
|
+
const findKey = (o, re) => Object.keys(o || {}).filter(k => re.test(k)).map(k => o[k]);
|
|
57
|
+
const findStr = o => Object.keys(o || {}).map(k => o[k]).find(v => typeof v === 'string');
|
|
58
|
+
|
|
59
|
+
const ACTION_CHECKS = {
|
|
60
|
+
'计算/度量': o => {
|
|
61
|
+
const n = Object.keys(o || {}).filter(k => isNum(o[k])).length;
|
|
62
|
+
const b = badNums(o);
|
|
63
|
+
return [OK('主指标为有限数', n > 0 && b.length === 0, b.length ? '非法数值:' + b.join(',') : n + ' 个数值')];
|
|
64
|
+
},
|
|
65
|
+
'生成/创造': o => [OK('非空生成', !!o && typeof o === 'object' && Object.keys(o).length > 0, '空对象视为生成失败')],
|
|
66
|
+
'识别/检测': o => {
|
|
67
|
+
const c = findKey(o, /置信|confidence|概率/);
|
|
68
|
+
return [OK('置信度在[0,1]内', c.length === 0 || c.every(v => isNum(v) && v >= 0 && v <= 1), c.join(',') || '无置信度字段')];
|
|
69
|
+
},
|
|
70
|
+
'预测/推演': o => {
|
|
71
|
+
const a = Object.keys(o || {}).map(k => o[k]).find(v => Array.isArray(v) && v.length > 0 && v.every(isNum));
|
|
72
|
+
const t = findStr(o);
|
|
73
|
+
return [OK('含定长数值序列', !!a, a ? a.length + ' 点' : '无数值序列'),
|
|
74
|
+
OK('趋势枚举合法', !t || /上升|下降|平稳|up|down|stable|升温|降温|持平/.test(t), String(t || '无'))];
|
|
75
|
+
},
|
|
76
|
+
'优化/调度': o => [OK('含分配结果', /got|alloc|分配|amount|数量/.test(JSON.stringify(o || {})), '')],
|
|
77
|
+
'同步/融合': o => {
|
|
78
|
+
const s = findKey(o, /同步度|融合度|一致/).filter(isNum);
|
|
79
|
+
return [OK('同步或融合度在[0,1]内', s.length === 0 || s.every(v => v >= 0 && v <= 1), s.join(',') || '无该字段')];
|
|
80
|
+
},
|
|
81
|
+
'监控/预警': o => {
|
|
82
|
+
const l = findStr(o);
|
|
83
|
+
return [OK('级别属于枚举集', !l || /green|yellow|orange|red|红|橙|黄|绿|low|medium|high/.test(l), String(l || '无级别'))];
|
|
84
|
+
},
|
|
85
|
+
'治理/审查': o => {
|
|
86
|
+
const c = findStr(o);
|
|
87
|
+
const probs = Object.keys(o || {}).map(k => o[k]).find(v => Array.isArray(v));
|
|
88
|
+
const pass = /通过/.test(String(c || ''));
|
|
89
|
+
return [OK('结论为通过或不通过', !c || /通过|不通过/.test(c), String(c || '无结论')),
|
|
90
|
+
OK('不通过时问题清单非空', pass || !probs || probs.length > 0, probs ? probs.length + ' 项' : '无清单')];
|
|
91
|
+
},
|
|
92
|
+
'存储/检索': o => [OK('非空返回', !!o && Object.keys(o).length > 0, '')],
|
|
93
|
+
'转换/映射': o => [OK('输出非空', !!o && Object.keys(o).length > 0, '')],
|
|
94
|
+
'—': o => [OK('结构非空且类型稳定', !!o && typeof o === 'object' && Object.keys(o).length > 0, '')],
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const DOMAIN_CHECKS = {
|
|
98
|
+
'生物人因': o => [OK('附免责声明软判据', true, /免责|不构成诊断|非医学/.test(JSON.stringify(o || {})) ? '已附' : '未附记录')],
|
|
99
|
+
'安全风控': o => [OK('默认拒绝语义可表达软判据', true, '')],
|
|
100
|
+
'金融经济': o => [OK('无浮点累加痕迹', !/\d\.\d{6,}/.test(JSON.stringify(o || {})), '')],
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const CONTRACTS = {};
|
|
104
|
+
|
|
105
|
+
/* 源1:元创造 468 条(V36.11 卷) */
|
|
106
|
+
try {
|
|
107
|
+
const t = fs.readFileSync(VOL, 'utf8');
|
|
108
|
+
const re = /^\| `(ATOM_[A-Z0-9_]+)` \| [^|]* \| ([^|]+) \| ([^|]+) \|/gm;
|
|
109
|
+
let m;
|
|
110
|
+
while ((m = re.exec(t))) CONTRACTS[m[1]] = { action: m[2].trim(), domain: m[3].trim(), src: '元创造V36.11' };
|
|
111
|
+
} catch (e) { /* R141 已确认合理:契约卷读取失败后,下方对【CONTRACTS 为空】有明确处理(CONTRACT_VOLUME_MISSING 并 exit(1)),非静默 */ }
|
|
112
|
+
if (Object.keys(CONTRACTS).length === 0) {
|
|
113
|
+
console.log('CONTRACT_VOLUME_MISSING: 契约卷不可读 ->', VOL);
|
|
114
|
+
if (IN_PACKAGE) { console.log('总判定:FAIL(包内契约卷缺失)'); process.exit(1); }
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* 源2:蓝本原有 124 条 */
|
|
118
|
+
try {
|
|
119
|
+
const g = JSON.parse(fs.readFileSync(GEN, 'utf8'));
|
|
120
|
+
const A2 = [['计算/度量', /计算|度量|评估|评分|量化|估计/], ['识别/检测', /识别|检测|判断|甄别/],
|
|
121
|
+
['预测/推演', /预测|推演|推断|外推/], ['优化/调度', /优化|调度|分配|排序/],
|
|
122
|
+
['转换/映射', /转换|映射|翻译|编码|解码|解析|提取/],
|
|
123
|
+
['同步/融合', /同步|融合|对齐|协同|合并/], ['生成/创造', /生成|创造|构建|设计/],
|
|
124
|
+
['监控/预警', /监控|监测|预警|告警/], ['治理/审查', /审查|治理|合规|校验|验证/],
|
|
125
|
+
['存储/检索', /存储|记忆|检索/]];
|
|
126
|
+
Object.keys(g.atoms || {}).forEach(id => {
|
|
127
|
+
const a = g.atoms[id];
|
|
128
|
+
if (!(a.input && a.output) || CONTRACTS[id]) return;
|
|
129
|
+
const nm = String(a.name || '');
|
|
130
|
+
let act = '—';
|
|
131
|
+
for (const pair of A2) { if (pair[1].test(nm)) { act = pair[0]; break; } }
|
|
132
|
+
CONTRACTS[id] = { action: act, domain: '—', src: '蓝本原有契约' };
|
|
133
|
+
});
|
|
134
|
+
} catch (e) {
|
|
135
|
+
/* 区分「GEN 表不存在」(允许跳过)与「存在但读坏了」(必须报错)。
|
|
136
|
+
否则解析失败会静默少 124 条契约,总数从 597 掉到 473 却照样 PASS。 */
|
|
137
|
+
const genExists = (function () { try { return !!GEN && fs.existsSync(GEN) } catch (x) { return false } })()
|
|
138
|
+
if (genExists) {
|
|
139
|
+
throw new Error('[R141-GEN-ATOMS] atoms_engines.json 存在但读取失败:' + e.message)
|
|
140
|
+
}
|
|
141
|
+
console.log('GEN_TABLE_MISSING: 蓝本原有契约表不可读,本层少统计 124 条 ->', GEN)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function validate(atomId, output) {
|
|
145
|
+
const c = CONTRACTS[atomId];
|
|
146
|
+
if (!c) return { pass: false, error: '该原子无契约', checks: [] };
|
|
147
|
+
const checks = [];
|
|
148
|
+
(ACTION_CHECKS[c.action] || ACTION_CHECKS['—'])(output).forEach(x => checks.push(x));
|
|
149
|
+
if (DOMAIN_CHECKS[c.domain]) DOMAIN_CHECKS[c.domain](output).forEach(x => checks.push(x));
|
|
150
|
+
return { pass: checks.every(x => x.ok), action: c.action, domain: c.domain, src: c.src, checks: checks };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = { validate: validate, CONTRACTS: CONTRACTS };
|
|
154
|
+
|
|
155
|
+
if (require.main === module) {
|
|
156
|
+
const E = require('./engine.cjs');
|
|
157
|
+
const ids = Object.keys(E.COMPUTE).filter(id => CONTRACTS[id]);
|
|
158
|
+
let pass = 0;
|
|
159
|
+
const bad = [];
|
|
160
|
+
ids.forEach(id => {
|
|
161
|
+
const r = E.run(id, E.SAMPLES[id] || {});
|
|
162
|
+
if (!r.success) return;
|
|
163
|
+
const v = validate(id, r.output);
|
|
164
|
+
if (v.pass) pass++; else bad.push([id, v]);
|
|
165
|
+
});
|
|
166
|
+
const bySrc = {};
|
|
167
|
+
Object.keys(CONTRACTS).forEach(k => { const s = CONTRACTS[k].src; bySrc[s] = (bySrc[s] || 0) + 1; });
|
|
168
|
+
console.log('='.repeat(72));
|
|
169
|
+
console.log('契约校验器自测');
|
|
170
|
+
console.log('='.repeat(72));
|
|
171
|
+
console.log('契约总数: ', Object.keys(CONTRACTS).length, JSON.stringify(bySrc));
|
|
172
|
+
console.log('compute 原子匹配契约: ', ids.length + ' / ' + Object.keys(E.COMPUTE).length);
|
|
173
|
+
console.log('契约校验 通过 ', pass, ' 失败 ', bad.length);
|
|
174
|
+
bad.slice(0, 8).forEach(pair => {
|
|
175
|
+
console.log(' FAIL ' + pair[0] + ' [' + pair[1].action);
|
|
176
|
+
pair[1].checks.filter(c => !c.ok).forEach(c => console.log(' - ' + c.n + ' ' + c.d));
|
|
177
|
+
});
|
|
178
|
+
// ---- R141:遍历**契约全量**(不再只遍历工厂自己的子集)----
|
|
179
|
+
// 旧版只遍历 F.CONTRACTS(473 条),导致 597-473-50=74 条从未被测试而总判定仍 PASS。
|
|
180
|
+
let fPass = 0, fFail = 0, fNoImpl = 0;
|
|
181
|
+
const noImpl = [];
|
|
182
|
+
try {
|
|
183
|
+
const F = require('./atom-factory.cjs');
|
|
184
|
+
const SAMPLE = [0.8, 0.6, 0.75, 0.9, 0.55];
|
|
185
|
+
const ALLOW_NO_IMPL = new Set([
|
|
186
|
+
...((F.EXTERNAL_NEEDED instanceof Set) ? [...F.EXTERNAL_NEEDED] : []),
|
|
187
|
+
...((F.MODEL_NEEDED instanceof Set) ? [...F.MODEL_NEEDED] : []),
|
|
188
|
+
]);
|
|
189
|
+
Object.keys(CONTRACTS).forEach(id => {
|
|
190
|
+
if (ids.indexOf(id) >= 0) return; // 已由手写 compute 实现覆盖
|
|
191
|
+
let fn = null;
|
|
192
|
+
try { fn = F.make(id); } catch (e) { fn = null; }
|
|
193
|
+
if (!fn) {
|
|
194
|
+
if (!ALLOW_NO_IMPL.has(id)) { fNoImpl++; if (noImpl.length < 20) noImpl.push(id); }
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
let out = null;
|
|
198
|
+
try { out = fn(SAMPLE); } catch (e) { out = null; }
|
|
199
|
+
const v = validate(id, out);
|
|
200
|
+
if (v.pass) fPass++; else { fFail++; if (bad.length < 8) bad.push([id, v]); }
|
|
201
|
+
});
|
|
202
|
+
} catch (e) { fFail = 1; }
|
|
203
|
+
console.log('工厂生成覆盖: 通过 ' + fPass + ' / 失败 ' + fFail + ' / 无实现 ' + fNoImpl);
|
|
204
|
+
if (noImpl.length) {
|
|
205
|
+
console.log(' 无实现(不在 EXTERNAL_NEEDED 白名单):');
|
|
206
|
+
noImpl.forEach(id => console.log(' - ' + id));
|
|
207
|
+
if (fNoImpl > noImpl.length) console.log(' … 共 ' + fNoImpl + ' 条');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const fail = bad.length + (ids.length === 0 ? 1 : 0) + fFail + fNoImpl;
|
|
211
|
+
console.log(fail === 0 ? '总判定:PASS' : '总判定:FAIL');
|
|
212
|
+
process.exit(fail === 0 ? 0 : 1);
|
|
213
|
+
}
|