@evomap/evolver-core 2.0.0-beta.19 → 2.0.0-beta.22

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.
Files changed (160) hide show
  1. package/assets/gep/genes.jsonl +5 -5
  2. package/dist/algo/bans.d.ts +10 -1
  3. package/dist/algo/bans.js +56 -6
  4. package/dist/algo/candidateAssembly.d.ts +25 -2
  5. package/dist/algo/candidateAssembly.js +143 -20
  6. package/dist/algo/capabilityCandidates.js +10 -0
  7. package/dist/algo/cycleEngine.d.ts +40 -5
  8. package/dist/algo/cycleEngine.js +277 -37
  9. package/dist/algo/evolutionEvent.d.ts +26 -0
  10. package/dist/algo/evolutionEvent.js +32 -0
  11. package/dist/algo/exploration.d.ts +7 -0
  12. package/dist/algo/exploration.js +16 -3
  13. package/dist/algo/geneHealth.d.ts +34 -1
  14. package/dist/algo/geneHealth.js +42 -0
  15. package/dist/algo/geneIntake.d.ts +46 -1
  16. package/dist/algo/geneIntake.js +121 -10
  17. package/dist/algo/geneSelection.d.ts +115 -6
  18. package/dist/algo/geneSelection.js +459 -32
  19. package/dist/algo/index.d.ts +4 -1
  20. package/dist/algo/index.js +4 -1
  21. package/dist/algo/kautoProjection.d.ts +41 -0
  22. package/dist/algo/kautoProjection.js +95 -0
  23. package/dist/algo/kautoValidator.d.ts +68 -0
  24. package/dist/algo/kautoValidator.js +256 -0
  25. package/dist/algo/orchestrator.d.ts +14 -1
  26. package/dist/algo/orchestrator.js +9 -2
  27. package/dist/algo/solidify.d.ts +11 -2
  28. package/dist/algo/solidify.js +37 -7
  29. package/dist/algo/ucb1.d.ts +53 -0
  30. package/dist/algo/ucb1.js +156 -0
  31. package/dist/assetrepair/hubRejection.d.ts +12 -0
  32. package/dist/assetrepair/hubRejection.js +109 -0
  33. package/dist/assetrepair/index.d.ts +2 -0
  34. package/dist/assetrepair/index.js +2 -0
  35. package/dist/assetrepair/repair.d.ts +33 -0
  36. package/dist/assetrepair/repair.js +155 -0
  37. package/dist/assetstore/assetSidecarRecords.js +5 -1
  38. package/dist/assetstore/assetStoreHealth.d.ts +2 -3
  39. package/dist/assetstore/assetStoreHealth.js +4 -10
  40. package/dist/assetstore/foreignJsonlSource.d.ts +48 -0
  41. package/dist/assetstore/foreignJsonlSource.js +150 -0
  42. package/dist/assetstore/index.d.ts +3 -0
  43. package/dist/assetstore/index.js +3 -0
  44. package/dist/assetstore/learningHistory.js +3 -3
  45. package/dist/assetstore/localAssetStoreSnapshot.d.ts +51 -0
  46. package/dist/assetstore/localAssetStoreSnapshot.js +329 -0
  47. package/dist/assetstore/localJsonl.d.ts +8 -0
  48. package/dist/assetstore/localJsonl.js +128 -3
  49. package/dist/assetstore/provenance.d.ts +38 -3
  50. package/dist/assetstore/provenance.js +103 -45
  51. package/dist/assetstore/provider.d.ts +4 -0
  52. package/dist/assetstore/reviewFilter.d.ts +19 -1
  53. package/dist/assetstore/reviewFilter.js +36 -0
  54. package/dist/assetstore/unionReadStore.d.ts +25 -0
  55. package/dist/assetstore/unionReadStore.js +119 -0
  56. package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
  57. package/dist/benchmark/antiGeneBenchmark.js +4 -3
  58. package/dist/benchmark/antiGeneRollout.d.ts +2 -0
  59. package/dist/benchmark/antiGeneRollout.js +4 -3
  60. package/dist/benchmark/index.d.ts +2 -1
  61. package/dist/benchmark/index.js +2 -1
  62. package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
  63. package/dist/benchmark/selectionFlatAbstention.js +481 -0
  64. package/dist/bootstrap/envFingerprint.d.ts +9 -0
  65. package/dist/bootstrap/envFingerprint.js +5 -0
  66. package/dist/bootstrap/index.d.ts +2 -1
  67. package/dist/bootstrap/index.js +2 -1
  68. package/dist/bootstrap/lifecycleBootstrap.d.ts +111 -0
  69. package/dist/bootstrap/lifecycleBootstrap.js +433 -0
  70. package/dist/bootstrap/v1EnvCompat.d.ts +3 -0
  71. package/dist/bootstrap/v1EnvCompat.js +48 -1
  72. package/dist/events/eventArchive.d.ts +2 -0
  73. package/dist/events/eventArchive.js +13 -3
  74. package/dist/events/eventSchema.d.ts +7 -7
  75. package/dist/events/eventStore.d.ts +2 -0
  76. package/dist/events/eventStore.js +5 -1
  77. package/dist/events/ingest.d.ts +2 -1
  78. package/dist/events/ingest.js +6 -0
  79. package/dist/exec/autoExec.d.ts +30 -3
  80. package/dist/exec/autoExec.js +294 -29
  81. package/dist/exec/autonomousCycle.d.ts +7 -0
  82. package/dist/exec/autonomousCycle.js +2 -0
  83. package/dist/exec/claudeBridge.d.ts +28 -6
  84. package/dist/exec/claudeBridge.js +411 -258
  85. package/dist/exec/executionBinding.d.ts +414 -0
  86. package/dist/exec/executionBinding.js +588 -0
  87. package/dist/exec/index.d.ts +1 -0
  88. package/dist/exec/index.js +1 -0
  89. package/dist/exec/proofOfWork.d.ts +1 -1
  90. package/dist/exec/proofOfWork.js +2 -2
  91. package/dist/exec/runnerRegistry.d.ts +5 -0
  92. package/dist/exec/runnerRegistry.js +54 -14
  93. package/dist/hub/capability.d.ts +40 -1
  94. package/dist/hub/conversationDistiller.d.ts +19 -0
  95. package/dist/hub/conversationDistiller.js +115 -37
  96. package/dist/hub/fake.d.ts +1 -0
  97. package/dist/hub/fake.js +1 -0
  98. package/dist/hub/index.d.ts +1 -0
  99. package/dist/hub/index.js +1 -0
  100. package/dist/hub/recipeCompose.d.ts +27 -0
  101. package/dist/hub/recipeCompose.js +90 -0
  102. package/dist/hub/sanitize.js +119 -5
  103. package/dist/index.d.ts +2 -0
  104. package/dist/index.js +2 -0
  105. package/dist/mailbox/ipcServer.d.ts +2 -0
  106. package/dist/mailbox/ipcServer.js +20 -0
  107. package/dist/mailbox/store.d.ts +52 -2
  108. package/dist/mailbox/store.js +546 -81
  109. package/dist/modelCompatibility.d.ts +164 -0
  110. package/dist/modelCompatibility.js +309 -0
  111. package/dist/observers/valueDigestObserver.d.ts +9 -0
  112. package/dist/observers/valueDigestObserver.js +35 -2
  113. package/dist/ops/cleanup.js +1 -1
  114. package/dist/ops/evolutionGraphProjection.d.ts +20 -0
  115. package/dist/ops/evolutionGraphProjection.js +315 -0
  116. package/dist/ops/index.d.ts +2 -1
  117. package/dist/ops/index.js +2 -1
  118. package/dist/ops/selfUpdate.d.ts +8 -0
  119. package/dist/ops/selfUpdate.js +24 -8
  120. package/dist/ops/valueOutreach.d.ts +3 -1
  121. package/dist/ops/valueOutreach.js +5 -1
  122. package/dist/personality/schema.d.ts +18 -18
  123. package/dist/schema/evolutionGraph.d.ts +784 -0
  124. package/dist/schema/evolutionGraph.js +187 -0
  125. package/dist/schema/index.d.ts +1 -0
  126. package/dist/schema/index.js +1 -0
  127. package/dist/schema/proofOfWork.d.ts +125 -6
  128. package/dist/schema/proofOfWork.js +102 -4
  129. package/dist/shadow/shadowHub.js +1 -0
  130. package/dist/signals/expand.d.ts +15 -1
  131. package/dist/signals/expand.js +148 -0
  132. package/dist/signals/index.d.ts +3 -1
  133. package/dist/signals/index.js +3 -1
  134. package/dist/signals/scopeVocabulary.d.ts +75 -0
  135. package/dist/signals/scopeVocabulary.js +91 -0
  136. package/dist/signals/taskDomain.d.ts +22 -0
  137. package/dist/signals/taskDomain.js +43 -0
  138. package/dist/trace/learningTrace.d.ts +7 -0
  139. package/dist/trace/learningTrace.js +22 -0
  140. package/dist/trace/trajectory.d.ts +8 -0
  141. package/dist/trace/trajectory.js +14 -2
  142. package/dist/util/fileLock.d.ts +92 -5
  143. package/dist/util/fileLock.js +809 -70
  144. package/dist/util/index.d.ts +2 -1
  145. package/dist/util/index.js +1 -1
  146. package/dist/verify/index.d.ts +2 -1
  147. package/dist/verify/index.js +1 -1
  148. package/dist/verify/sandboxRunner.d.ts +2 -0
  149. package/dist/verify/sandboxRunner.js +154 -10
  150. package/dist/verify/sandboxedValidation.d.ts +7 -2
  151. package/dist/verify/sandboxedValidation.js +102 -24
  152. package/dist/verify/validation.d.ts +24 -3
  153. package/dist/verify/validation.js +141 -24
  154. package/dist/wire/geneHints.d.ts +88 -16
  155. package/dist/wire/geneHints.js +124 -15
  156. package/dist/wire/index.d.ts +8 -3
  157. package/dist/wire/index.js +2 -2
  158. package/dist/wire/schemaGate.d.ts +21 -0
  159. package/dist/wire/schemaGate.js +119 -10
  160. package/package.json +5 -4
@@ -1,6 +1,70 @@
1
1
  // With shell:false these are passed literally (harmless), but their presence means an injection attempt
2
2
  // or a command that wrongly assumes a shell (e.g. `a && b`) — reject loudly so it is split, not silently mis-run.
3
3
  export const SHELL_METACHARS = /[;&|`$<>\n\r]/;
4
+ /**
5
+ * Parse one validation command without invoking a shell. Quotes group whitespace and backslash only escapes
6
+ * whitespace, quotes, or another backslash; no variable expansion or command substitution is performed.
7
+ * A null result means the command has an unterminated quote and must be rejected.
8
+ */
9
+ export function tokenizeValidationCommand(command) {
10
+ const value = String(command ?? '');
11
+ const tokens = [];
12
+ let current = '';
13
+ let tokenStarted = false;
14
+ let quote = null;
15
+ let escaped = false;
16
+ for (let index = 0; index < value.length; index += 1) {
17
+ const ch = value[index];
18
+ if (escaped) {
19
+ current += ch;
20
+ tokenStarted = true;
21
+ escaped = false;
22
+ continue;
23
+ }
24
+ if (ch === '\\' && quote !== "'") {
25
+ const next = value[index + 1];
26
+ if (next !== undefined && (/\s/.test(next) || next === '"' || next === "'" || next === '\\')) {
27
+ escaped = true;
28
+ tokenStarted = true;
29
+ continue;
30
+ }
31
+ }
32
+ if (quote !== null) {
33
+ if (ch === quote) {
34
+ quote = null;
35
+ }
36
+ else {
37
+ current += ch;
38
+ }
39
+ tokenStarted = true;
40
+ continue;
41
+ }
42
+ if (ch === '"' || ch === "'") {
43
+ quote = ch;
44
+ tokenStarted = true;
45
+ continue;
46
+ }
47
+ if (/\s/.test(ch)) {
48
+ if (tokenStarted) {
49
+ tokens.push(current);
50
+ current = '';
51
+ tokenStarted = false;
52
+ }
53
+ continue;
54
+ }
55
+ current += ch;
56
+ tokenStarted = true;
57
+ }
58
+ if (quote !== null)
59
+ return null;
60
+ if (escaped) {
61
+ current += '\\';
62
+ tokenStarted = true;
63
+ }
64
+ if (tokenStarted)
65
+ tokens.push(current);
66
+ return tokens;
67
+ }
4
68
  // Node flags that turn `node` into an arbitrary-code evaluator or preload hook. A legit validation command is
5
69
  // `node <script> [args]`; these flags must be denied by the sandbox and must never be hidden by missing-script skip.
6
70
  export const BLOCKED_NODE_FLAGS = new Set([
@@ -12,6 +76,10 @@ export const BLOCKED_NODE_FLAGS = new Set([
12
76
  '--inspect', '--inspect-brk', '--inspect-port', '--inspect-publish-uid',
13
77
  // Watch: keeps the process alive past its work → hangs validation until the sandbox SIGKILLs it (DoS).
14
78
  '--watch', '--watch-path', '--watch-preserve-output',
79
+ // Package/test runners execute code selected from package metadata or the checkout, not one declared script.
80
+ '--run', '--test',
81
+ // Input-type changes stdin into an evaluator; validation must always name a script explicitly.
82
+ '--input-type', '-',
15
83
  // Module-resolution override: can redirect imports/requires to attacker-chosen code paths.
16
84
  '--conditions', '-C',
17
85
  ]);
@@ -28,32 +96,72 @@ export function nodeFlagViolation(executable, args) {
28
96
  if (!isNodeExecutable(executable))
29
97
  return null;
30
98
  for (const a of args) {
99
+ // Node stops interpreting its own flags at the first script (or `--` delimiter). Anything after that is
100
+ // an argv value owned by the script, even when it happens to match a blocked Node option name.
101
+ if (a === '--' || !a.startsWith('-'))
102
+ return null;
31
103
  const flag = a.split('=')[0] ?? a;
32
104
  if (BLOCKED_NODE_FLAGS.has(flag))
33
105
  return flag;
34
106
  }
35
107
  return null;
36
108
  }
109
+ const SAFE_NODE_SCRIPT_FLAGS = new Set(['-c', '--check']);
110
+ const SAFE_NODE_NO_SCRIPT_FLAGS = new Set(['-v', '--version', '-h', '--help']);
111
+ /**
112
+ * 将 Node 命令限制为明确的脚本位置,防止带参数的选项吞掉下一个 token 后绕过脚本路径检查。
113
+ * 验证只需要普通脚本、语法检查,以及兼容旧 Gene 的 version/help 身份检查;其他前置选项默认拒绝。
114
+ */
115
+ export function classifyNodeValidationInvocation(executable, args) {
116
+ if (!isNodeExecutable(executable))
117
+ return { kind: 'invalid' };
118
+ const blocked = nodeFlagViolation(executable, args);
119
+ if (blocked)
120
+ return { kind: 'invalid', option: blocked };
121
+ if (args.length === 1 && SAFE_NODE_NO_SCRIPT_FLAGS.has(args[0])) {
122
+ return { kind: 'safe_no_script' };
123
+ }
124
+ let index = 0;
125
+ let afterEndOfOptions = false;
126
+ while (index < args.length) {
127
+ const token = args[index];
128
+ if (token === '--') {
129
+ afterEndOfOptions = true;
130
+ index += 1;
131
+ break;
132
+ }
133
+ if (SAFE_NODE_SCRIPT_FLAGS.has(token)) {
134
+ index += 1;
135
+ continue;
136
+ }
137
+ if (token.startsWith('-')) {
138
+ return { kind: 'invalid', option: token.split('=')[0] ?? token };
139
+ }
140
+ break;
141
+ }
142
+ const script = args[index];
143
+ if (!script || (!afterEndOfOptions && script.startsWith('-')))
144
+ return { kind: 'invalid' };
145
+ return { kind: 'script', script };
146
+ }
37
147
  /** 命令首 token(可执行名)是否在项目声明的 allowlist 内. */
38
148
  export function isAllowed(cmd, allowlist) {
39
- const head = cmd.trim().split(/\s+/)[0] ?? '';
149
+ const tokens = tokenizeValidationCommand(cmd);
150
+ const head = tokens?.[0] ?? '';
40
151
  return allowlist.includes(head);
41
152
  }
42
- /** Extract the local script targeted by `node <script> ...`, or null for non-script node commands. */
153
+ /** Extract the unambiguous script targeted by `node <script> ...`, or null for non-script/unsupported commands. */
43
154
  export function validationScriptPath(cmd) {
44
- const tokens = String(cmd ?? '').trim().split(/\s+/);
155
+ const tokens = tokenizeValidationCommand(cmd);
156
+ if (!tokens || tokens.length < 2)
157
+ return null;
45
158
  const executable = tokens[0] ?? '';
46
- if (tokens.length < 2 || !isNodeExecutable(executable))
159
+ if (!isNodeExecutable(executable))
47
160
  return null;
48
- if (SHELL_METACHARS.test(cmd) || nodeFlagViolation(executable, tokens.slice(1)))
161
+ if (SHELL_METACHARS.test(cmd))
49
162
  return null;
50
- for (let i = 1; i < tokens.length; i += 1) {
51
- const token = tokens[i];
52
- if (token.startsWith('-'))
53
- continue;
54
- return /\.(?:c|m)?js$/.test(token) ? token : null;
55
- }
56
- return null;
163
+ const invocation = classifyNodeValidationInvocation(executable, tokens.slice(1));
164
+ return invocation.kind === 'script' ? invocation.script : null;
57
165
  }
58
166
  /** stdout 摘要 = 首行 + 末行(去 canary.js 隐形约定: 不找魔法字符串, 只留可读摘要). */
59
167
  export function summarizeStdout(stdout) {
@@ -68,20 +176,30 @@ export function summarizeStdout(stdout) {
68
176
  * 跑校验(M4A-4). 判价值 = **exit code + stdout 摘要**, 不依赖 canary.js 魔法字符串(批注#22).
69
177
  * 不在 allowlist 的命令 auto-deny(不执行, allowed=false), 守无人值守安全.
70
178
  */
71
- export async function runValidation(plan, run) {
179
+ export async function runValidation(plan, run, signal) {
72
180
  const results = [];
181
+ let cancelled = signal?.aborted === true;
73
182
  for (const c of plan.commands) {
183
+ if (signal?.aborted) {
184
+ cancelled = true;
185
+ break;
186
+ }
74
187
  const label = c.label ?? c.cmd;
75
188
  if (!isAllowed(c.cmd, plan.allowlist)) {
76
189
  results.push({ label, cmd: c.cmd, allowed: false, exitCode: null, stdoutSummary: '', passed: false });
77
190
  continue;
78
191
  }
79
- const out = await run(c.cmd);
192
+ const out = await run(c.cmd, signal);
80
193
  results.push({ label, cmd: c.cmd, allowed: true, exitCode: out.exitCode, stdoutSummary: summarizeStdout(out.stdout), passed: out.exitCode === 0 });
194
+ // runner 可能在返回结果后才观察到取消;此时不能让完整的 exit-0 列表伪装成通过。
195
+ if (signal?.aborted) {
196
+ cancelled = true;
197
+ break;
198
+ }
81
199
  }
82
200
  // 全部 allowed 的命令都 exit 0 才算通过; 有命令被 deny 视为未通过(校验不完整)
83
- const passed = results.length > 0 && results.every((r) => r.allowed && r.passed);
84
- return { results, passed };
201
+ const passed = !cancelled && results.length > 0 && results.every((r) => r.allowed && r.passed);
202
+ return { results, passed, cancelled };
85
203
  }
86
204
  /**
87
205
  * 检查验证命令是否安全可作为 Gene.validation 条目使用(忠实移植 v1 policyCheck.isValidationCommandAllowed)。
@@ -96,9 +214,6 @@ export function isValidationCommandAllowed(cmd) {
96
214
  const c = String(cmd || '').trim();
97
215
  if (!c)
98
216
  return false;
99
- // 只允许 node 命令作为验证命令
100
- if (!c.startsWith('node '))
101
- return false;
102
217
  // 不允许命令替换
103
218
  if (/`|\$\(/.test(c))
104
219
  return false;
@@ -106,11 +221,13 @@ export function isValidationCommandAllowed(cmd) {
106
221
  const stripped = c.replace(/"[^"]*"/g, '').replace(/'[^']*'/g, '');
107
222
  if (SHELL_METACHARS.test(stripped))
108
223
  return false;
109
- // 检查被阻止的 node 标志
110
- const tokens = c.split(/\s+/);
224
+ // 检查被阻止或会让脚本位置产生歧义的 node 标志
225
+ const tokens = tokenizeValidationCommand(c);
226
+ if (!tokens)
227
+ return false;
111
228
  const executable = tokens[0] ?? '';
112
- const args = tokens.slice(1);
113
- if (nodeFlagViolation(executable, args))
229
+ if (executable !== 'node')
114
230
  return false;
115
- return true;
231
+ const args = tokens.slice(1);
232
+ return classifyNodeValidationInvocation(executable, args).kind !== 'invalid';
116
233
  }
@@ -3,15 +3,14 @@
3
3
  * router (routing_hint) or restrict tools (tool_policy). Ported from v1 src/gep/schemas/gene.js (PR #93,
4
4
  * "wire routing_hint and tool_policy into Gene schema").
5
5
  *
6
- * v2-delta (feature-gate): these fields are NOT yet in @evomap/gep-sdk's gene.schema.json
7
- * (additionalProperties:false), so a Gene carrying them is not a schema-valid gep-sdk asset until a
8
- * gep-sdk gene-schema bump exactly how Capsule's proof_of_work / resolution_status were v2-delta before
9
- * the 1.11.0 bump made them first-class. That invalidity is surfaced ONLY by the advisory validateWire
10
- * (wire/schemaGate) at intake on the hint-stripped core, and via the evolver_gep_build pre-publish
11
- * preview — plus the hub's own schema check on receipt; there is NO enforced local egress gate (the
12
- * publish/egress path is sanitize-only and does not call validateWire). Until a bump the hints ride along
13
- * LOCALLY (intake pool + v1→v2 import fidelity); nothing in this repo wires them to a runtime consumer yet
14
- * (the proxy model router's `gene_hint` seam is the eventual tier consumer — see
6
+ * routing_hint / tool_policy and the K_auto coordinates are first-class in @evomap/gep-sdk 1.13.0, so they
7
+ * are normalized here rather than stripped. generation_meta and model_name remain local-only annotations for
8
+ * now. The advisory validateWire still surfaces any malformed shape at intake on the local-only slice, and
9
+ * via the evolver_gep_build pre-publish preview plus the hub's own schema check on receipt; there is NO
10
+ * enforced local egress gate (the publish/egress path is sanitize-only and does not call validateWire).
11
+ *
12
+ * Until a future schema bump, nothing in this repo wires these annotations to a runtime consumer yet (the
13
+ * proxy model router's `gene_hint` seam is the eventual tier consumer see
15
14
  * packages/evolver-proxy/src/router/modelRouter.ts).
16
15
  *
17
16
  * Enum strings are matched case-sensitively by the consuming router / tool-gate — keep them EXACT. The
@@ -55,7 +54,7 @@ export interface GeneGenerationHeuristics {
55
54
  has_corrective_insight?: boolean;
56
55
  }
57
56
  /**
58
- * The full provenance + quality metadata block (V1 `gene._source`). Lives on Gene as the v2-delta field
57
+ * The full provenance + quality metadata block (V1 `gene._source`). Lives on Gene as the local-only field
59
58
  * `generation_meta`. `source` is the only required key; the rest is descriptive for reviewers / future
60
59
  * governance. `quality_score` is a coarse [0,1] tier-anchored score (evolved 0.7 / distilled 0.4 / manual 0.3
61
60
  * baseline + bonuses); `overcame_errors` is the mutation_log copy that the trajectory overcame.
@@ -67,12 +66,56 @@ export interface GenerationMeta {
67
66
  overcame_errors?: string[];
68
67
  }
69
68
  /**
70
- * The v2-delta hint field names, in one place the intake gate strips these before the gep-sdk schema check.
71
- * IMPORTANT: when a gep-sdk gene-schema bump makes one of these first-class, REMOVE it from this list in the
72
- * same change. Otherwise intakeGene keeps stripping a now-validated field before validateWire (fail-open the
73
- * field's new schema constraints go unchecked at intake) while asset_id still commits it.
69
+ * K_auto projection-key coordinates a Gene MAY carry so its record is machine-decidable in the strict
70
+ * automatic-governance subdomain (paper §K_auto; validator: algo/kautoValidator.ts). These four fields are the
71
+ * DEDICATED, structured form of the coordinates that production previously expressed only through proxy fields
72
+ * (category≈claim, signals_match≈scope, model_name≈runtime, validation≈verifier). The strict measurement
73
+ * (bench/thesis/result-kauto-strict.json) found the dedicated fields populated at 0% and three coordinates
74
+ * (version/claim/scope) undecidable for 100% of 5,665 real rows — the writer side simply never emitted them.
75
+ *
76
+ * Shapes mirror gep-sdk 1.13.0 gene.schema.json (PR: add Gene K_auto coordinates), the schema-authoritative
77
+ * definition, EXACTLY so a gene minted here validates once the SDK bump lands:
78
+ * claims: {predicate:string, kind?:'behavioral'|'structural'|'performance'|'safety'}[]
79
+ * scope: {signals:string[], predicate?:string}
80
+ * runtime_profile: {runtime:string, env_class?:'ci'|'local'|'prod'|'sandbox'}
81
+ * verifier_profile: {verifier:string, decision?:'pass'|'fail'|'inconclusive'}
82
+ *
83
+ * Since gep-sdk 1.13.0, these four coordinates are first-class Gene fields: the intake schema gate validates
84
+ * their dedicated structure instead of stripping them as local-only hints. They still ride along in asset_id
85
+ * (canonicalize hashes every own key), so a silent strip on the hub side would change the hashed bytes and fail
86
+ * gene_asset_id_verification_failed; the hub allowlist admits them for exactly this reason.
87
+ */
88
+ export declare const CLAIM_KINDS: readonly ["behavioral", "structural", "performance", "safety"];
89
+ export type ClaimKind = (typeof CLAIM_KINDS)[number];
90
+ export interface GeneClaim {
91
+ predicate: string;
92
+ kind?: ClaimKind;
93
+ }
94
+ export declare const ENV_CLASSES: readonly ["ci", "local", "prod", "sandbox"];
95
+ export type EnvClass = (typeof ENV_CLASSES)[number];
96
+ export interface GeneRuntimeProfile {
97
+ runtime: string;
98
+ env_class?: EnvClass;
99
+ }
100
+ export declare const VERIFIER_DECISIONS: readonly ["pass", "fail", "inconclusive"];
101
+ export type VerifierDecision = (typeof VERIFIER_DECISIONS)[number];
102
+ export interface GeneVerifierProfile {
103
+ verifier: string;
104
+ decision?: VerifierDecision;
105
+ }
106
+ export interface GeneScope {
107
+ signals: string[];
108
+ predicate?: string;
109
+ }
110
+ /**
111
+ * The still-local-only Gene field names, in one place — the intake gate strips these before the gep-sdk schema
112
+ * check. IMPORTANT: when a gep-sdk gene-schema bump makes one of these first-class, REMOVE it from this list in
113
+ * the same change. Otherwise intakeGene keeps stripping a now-validated field before validateWire (fail-open —
114
+ * the field's new schema constraints go unchecked at intake) while asset_id still commits it.
115
+ *
116
+ * Only generation_meta and model_name remain local-only annotations for now, so the strip list is just those two.
74
117
  */
75
- export declare const GENE_HINT_FIELDS: readonly ["routing_hint", "tool_policy", "generation_meta"];
118
+ export declare const GENE_HINT_FIELDS: readonly ["generation_meta", "model_name"];
76
119
  /**
77
120
  * Normalize an arbitrary routing_hint fragment to a strict { tier?, reasoning_level? } object, or null.
78
121
  * Unknown enum values are dropped (a stray tier would fail the consumer's exhaustive match and route as if
@@ -101,5 +144,34 @@ export declare function normalizeToolPolicy(raw: unknown): GeneToolPolicy | null
101
144
  * alone is a meaningful provenance tag); only a missing/unknown source yields null.
102
145
  */
103
146
  export declare function normalizeGenerationMeta(raw: unknown): GenerationMeta | null;
104
- /** Strip the v2-delta hint fields from a gene-shaped object (used to validate the gep-sdk-known core). */
147
+ /**
148
+ * Normalize an arbitrary claims fragment to a strict GeneClaim[] or null. A claim survives only with a
149
+ * non-empty string `predicate`; `kind` is kept only if it is one of the closed enum members (a stray kind is
150
+ * dropped, mirroring the enum typeguards for tier/severity). Predicates are trimmed and length-bounded so a
151
+ * runaway string cannot bloat the hashed bytes. An empty result → null ("no explicit claim"), which keeps the
152
+ * gene OUT of strict K_auto rather than fabricating a coordinate.
153
+ */
154
+ export declare function normalizeClaims(raw: unknown): GeneClaim[] | null;
155
+ /**
156
+ * Normalize an arbitrary scope fragment to a strict { signals, predicate? } object or null. `signals` keeps only
157
+ * non-empty trimmed strings; the block collapses to null when none survive (an empty signal list is not a scope).
158
+ * `predicate` is kept only as a non-empty trimmed string. Deliberately lossy like the hint normalizers.
159
+ */
160
+ export declare function normalizeGeneScope(raw: unknown): GeneScope | null;
161
+ /**
162
+ * Normalize an arbitrary runtime_profile fragment to { runtime, env_class? } or null. `runtime` must be a
163
+ * non-empty trimmed string (the coordinate is meaningless without it); `env_class` is kept only if it is a
164
+ * closed enum member. Note this is DISTINCT from the flat `model_name` field — model_name records WHICH LLM
165
+ * produced the gene (an authorship/tier signal); runtime_profile records the EXECUTION environment class the
166
+ * claims were established under. A producer may set either, both, or neither.
167
+ */
168
+ export declare function normalizeRuntimeProfile(raw: unknown): GeneRuntimeProfile | null;
169
+ /**
170
+ * Normalize an arbitrary verifier_profile fragment to { verifier, decision? } or null. `verifier` must be a
171
+ * non-empty trimmed string; `decision` is kept only if it is a closed enum member. This is the verifier IDENTITY
172
+ * axis (e.g. 'npm-test', 'gep-verify@1.4'); the substantive-command bar the strict validator applies is checked
173
+ * downstream in kautoValidator.decideVerifier, not here — this layer only shapes the field.
174
+ */
175
+ export declare function normalizeVerifierProfile(raw: unknown): GeneVerifierProfile | null;
176
+ /** Strip only local-only Gene annotations before validating against the gep-sdk schema. */
105
177
  export declare function stripGeneHints(gene: Record<string, unknown>): Record<string, unknown>;
@@ -3,15 +3,14 @@
3
3
  * router (routing_hint) or restrict tools (tool_policy). Ported from v1 src/gep/schemas/gene.js (PR #93,
4
4
  * "wire routing_hint and tool_policy into Gene schema").
5
5
  *
6
- * v2-delta (feature-gate): these fields are NOT yet in @evomap/gep-sdk's gene.schema.json
7
- * (additionalProperties:false), so a Gene carrying them is not a schema-valid gep-sdk asset until a
8
- * gep-sdk gene-schema bump exactly how Capsule's proof_of_work / resolution_status were v2-delta before
9
- * the 1.11.0 bump made them first-class. That invalidity is surfaced ONLY by the advisory validateWire
10
- * (wire/schemaGate) at intake on the hint-stripped core, and via the evolver_gep_build pre-publish
11
- * preview — plus the hub's own schema check on receipt; there is NO enforced local egress gate (the
12
- * publish/egress path is sanitize-only and does not call validateWire). Until a bump the hints ride along
13
- * LOCALLY (intake pool + v1→v2 import fidelity); nothing in this repo wires them to a runtime consumer yet
14
- * (the proxy model router's `gene_hint` seam is the eventual tier consumer — see
6
+ * routing_hint / tool_policy and the K_auto coordinates are first-class in @evomap/gep-sdk 1.13.0, so they
7
+ * are normalized here rather than stripped. generation_meta and model_name remain local-only annotations for
8
+ * now. The advisory validateWire still surfaces any malformed shape at intake on the local-only slice, and
9
+ * via the evolver_gep_build pre-publish preview plus the hub's own schema check on receipt; there is NO
10
+ * enforced local egress gate (the publish/egress path is sanitize-only and does not call validateWire).
11
+ *
12
+ * Until a future schema bump, nothing in this repo wires these annotations to a runtime consumer yet (the
13
+ * proxy model router's `gene_hint` seam is the eventual tier consumer see
15
14
  * packages/evolver-proxy/src/router/modelRouter.ts).
16
15
  *
17
16
  * Enum strings are matched case-sensitively by the consuming router / tool-gate — keep them EXACT. The
@@ -32,12 +31,37 @@ export const TOOL_POLICY_SEVERITIES = ['warn', 'block'];
32
31
  */
33
32
  export const GENERATION_SOURCES = ['evolved', 'distilled', 'manual'];
34
33
  /**
35
- * The v2-delta hint field names, in one place the intake gate strips these before the gep-sdk schema check.
36
- * IMPORTANT: when a gep-sdk gene-schema bump makes one of these first-class, REMOVE it from this list in the
37
- * same change. Otherwise intakeGene keeps stripping a now-validated field before validateWire (fail-open the
38
- * field's new schema constraints go unchecked at intake) while asset_id still commits it.
34
+ * K_auto projection-key coordinates a Gene MAY carry so its record is machine-decidable in the strict
35
+ * automatic-governance subdomain (paper §K_auto; validator: algo/kautoValidator.ts). These four fields are the
36
+ * DEDICATED, structured form of the coordinates that production previously expressed only through proxy fields
37
+ * (category≈claim, signals_match≈scope, model_name≈runtime, validation≈verifier). The strict measurement
38
+ * (bench/thesis/result-kauto-strict.json) found the dedicated fields populated at 0% and three coordinates
39
+ * (version/claim/scope) undecidable for 100% of 5,665 real rows — the writer side simply never emitted them.
40
+ *
41
+ * Shapes mirror gep-sdk 1.13.0 gene.schema.json (PR: add Gene K_auto coordinates), the schema-authoritative
42
+ * definition, EXACTLY so a gene minted here validates once the SDK bump lands:
43
+ * claims: {predicate:string, kind?:'behavioral'|'structural'|'performance'|'safety'}[]
44
+ * scope: {signals:string[], predicate?:string}
45
+ * runtime_profile: {runtime:string, env_class?:'ci'|'local'|'prod'|'sandbox'}
46
+ * verifier_profile: {verifier:string, decision?:'pass'|'fail'|'inconclusive'}
47
+ *
48
+ * Since gep-sdk 1.13.0, these four coordinates are first-class Gene fields: the intake schema gate validates
49
+ * their dedicated structure instead of stripping them as local-only hints. They still ride along in asset_id
50
+ * (canonicalize hashes every own key), so a silent strip on the hub side would change the hashed bytes and fail
51
+ * gene_asset_id_verification_failed; the hub allowlist admits them for exactly this reason.
39
52
  */
40
- export const GENE_HINT_FIELDS = ['routing_hint', 'tool_policy', 'generation_meta'];
53
+ export const CLAIM_KINDS = ['behavioral', 'structural', 'performance', 'safety'];
54
+ export const ENV_CLASSES = ['ci', 'local', 'prod', 'sandbox'];
55
+ export const VERIFIER_DECISIONS = ['pass', 'fail', 'inconclusive'];
56
+ /**
57
+ * The still-local-only Gene field names, in one place — the intake gate strips these before the gep-sdk schema
58
+ * check. IMPORTANT: when a gep-sdk gene-schema bump makes one of these first-class, REMOVE it from this list in
59
+ * the same change. Otherwise intakeGene keeps stripping a now-validated field before validateWire (fail-open —
60
+ * the field's new schema constraints go unchecked at intake) while asset_id still commits it.
61
+ *
62
+ * Only generation_meta and model_name remain local-only annotations for now, so the strip list is just those two.
63
+ */
64
+ export const GENE_HINT_FIELDS = ['generation_meta', 'model_name'];
41
65
  function includesEnum(set, v) {
42
66
  return typeof v === 'string' && set.includes(v);
43
67
  }
@@ -140,7 +164,92 @@ export function normalizeGenerationMeta(raw) {
140
164
  out.overcame_errors = errs;
141
165
  return out;
142
166
  }
143
- /** Strip the v2-delta hint fields from a gene-shaped object (used to validate the gep-sdk-known core). */
167
+ /**
168
+ * Normalize an arbitrary claims fragment to a strict GeneClaim[] or null. A claim survives only with a
169
+ * non-empty string `predicate`; `kind` is kept only if it is one of the closed enum members (a stray kind is
170
+ * dropped, mirroring the enum typeguards for tier/severity). Predicates are trimmed and length-bounded so a
171
+ * runaway string cannot bloat the hashed bytes. An empty result → null ("no explicit claim"), which keeps the
172
+ * gene OUT of strict K_auto rather than fabricating a coordinate.
173
+ */
174
+ export function normalizeClaims(raw) {
175
+ if (!Array.isArray(raw))
176
+ return null;
177
+ const out = [];
178
+ for (const item of raw) {
179
+ if (!item || typeof item !== 'object')
180
+ continue;
181
+ const r = item;
182
+ const predicate = typeof r['predicate'] === 'string' ? r['predicate'].trim().slice(0, 500) : '';
183
+ if (!predicate)
184
+ continue;
185
+ const claim = { predicate };
186
+ if (includesEnum(CLAIM_KINDS, r['kind']))
187
+ claim.kind = r['kind'];
188
+ out.push(claim);
189
+ }
190
+ return out.length > 0 ? out : null;
191
+ }
192
+ /**
193
+ * Normalize an arbitrary scope fragment to a strict { signals, predicate? } object or null. `signals` keeps only
194
+ * non-empty trimmed strings; the block collapses to null when none survive (an empty signal list is not a scope).
195
+ * `predicate` is kept only as a non-empty trimmed string. Deliberately lossy like the hint normalizers.
196
+ */
197
+ export function normalizeGeneScope(raw) {
198
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
199
+ return null;
200
+ const r = raw;
201
+ // Trim signals and drop whitespace-only ones (cleanToolList keeps by raw length, which would leak ' ' and an
202
+ // untrimmed ' x ' into the hashed bytes). A scope signal is an identity/constraint term, so its canonical form
203
+ // is the trimmed token — the strict validator reads it trimmed anyway (decideScope maps through str()).
204
+ const signals = Array.isArray(r['signals'])
205
+ ? r['signals'].filter((x) => typeof x === 'string').map((s) => s.trim()).filter((s) => s.length > 0)
206
+ : [];
207
+ if (signals.length === 0)
208
+ return null;
209
+ const out = { signals };
210
+ const predicate = typeof r['predicate'] === 'string' ? r['predicate'].trim().slice(0, 500) : '';
211
+ if (predicate)
212
+ out.predicate = predicate;
213
+ return out;
214
+ }
215
+ /**
216
+ * Normalize an arbitrary runtime_profile fragment to { runtime, env_class? } or null. `runtime` must be a
217
+ * non-empty trimmed string (the coordinate is meaningless without it); `env_class` is kept only if it is a
218
+ * closed enum member. Note this is DISTINCT from the flat `model_name` field — model_name records WHICH LLM
219
+ * produced the gene (an authorship/tier signal); runtime_profile records the EXECUTION environment class the
220
+ * claims were established under. A producer may set either, both, or neither.
221
+ */
222
+ export function normalizeRuntimeProfile(raw) {
223
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
224
+ return null;
225
+ const r = raw;
226
+ const runtime = typeof r['runtime'] === 'string' ? r['runtime'].trim().slice(0, 100) : '';
227
+ if (!runtime)
228
+ return null;
229
+ const out = { runtime };
230
+ if (includesEnum(ENV_CLASSES, r['env_class']))
231
+ out.env_class = r['env_class'];
232
+ return out;
233
+ }
234
+ /**
235
+ * Normalize an arbitrary verifier_profile fragment to { verifier, decision? } or null. `verifier` must be a
236
+ * non-empty trimmed string; `decision` is kept only if it is a closed enum member. This is the verifier IDENTITY
237
+ * axis (e.g. 'npm-test', 'gep-verify@1.4'); the substantive-command bar the strict validator applies is checked
238
+ * downstream in kautoValidator.decideVerifier, not here — this layer only shapes the field.
239
+ */
240
+ export function normalizeVerifierProfile(raw) {
241
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
242
+ return null;
243
+ const r = raw;
244
+ const verifier = typeof r['verifier'] === 'string' ? r['verifier'].trim().slice(0, 100) : '';
245
+ if (!verifier)
246
+ return null;
247
+ const out = { verifier };
248
+ if (includesEnum(VERIFIER_DECISIONS, r['decision']))
249
+ out.decision = r['decision'];
250
+ return out;
251
+ }
252
+ /** Strip only local-only Gene annotations before validating against the gep-sdk schema. */
144
253
  export function stripGeneHints(gene) {
145
254
  const hidden = GENE_HINT_FIELDS;
146
255
  const out = {};
@@ -2,7 +2,7 @@
2
2
  * 资产 wire 层. SSOT = @evomap/gep-sdk/schemas/*.schema.json (D19).
3
3
  * 字段一律 snake_case 锁定 (asset_id 跨实现契约); 本仓不发明 wire 字段, 只镜像 + 重导出工具.
4
4
  */
5
- import type { GeneRoutingHint, GeneToolPolicy, GenerationMeta } from './geneHints.js';
5
+ import type { GeneRoutingHint, GeneToolPolicy, GenerationMeta, GeneClaim, GeneScope, GeneRuntimeProfile, GeneVerifierProfile } from './geneHints.js';
6
6
  export { SCHEMA_VERSION, canonicalize, computeAssetId, verifyAssetId } from '@evomap/gep-sdk';
7
7
  export type GepCategory = typeof import('@evomap/gep-sdk').GEP_GENE_CATEGORIES[number];
8
8
  export type OutcomeStatus = typeof import('@evomap/gep-sdk').GEP_OUTCOME_STATUSES[number];
@@ -35,6 +35,11 @@ export interface Gene {
35
35
  routing_hint?: GeneRoutingHint | null;
36
36
  tool_policy?: GeneToolPolicy | null;
37
37
  generation_meta?: GenerationMeta | null;
38
+ model_name?: string;
39
+ claims?: GeneClaim[] | null;
40
+ scope?: GeneScope | null;
41
+ runtime_profile?: GeneRuntimeProfile | null;
42
+ verifier_profile?: GeneVerifierProfile | null;
38
43
  asset_id: string;
39
44
  }
40
45
  /** Capsule = 表现型/纯进化产物 (capsule.schema.json). */
@@ -99,5 +104,5 @@ export interface Mutation {
99
104
  expected_effect: string;
100
105
  risk_level: RiskLevel;
101
106
  }
102
- export { validateWire, schemaProperties, type WireValidation } from './schemaGate.js';
103
- export { ROUTING_TIERS, REASONING_LEVELS, TOOL_POLICY_SEVERITIES, GENERATION_SOURCES, GENE_HINT_FIELDS, normalizeRoutingHint, normalizeToolPolicy, normalizeGenerationMeta, stripGeneHints, type RoutingTier, type ReasoningLevel, type ToolPolicySeverity, type GenerationSource, type GeneRoutingHint, type GeneToolPolicy, type GeneGenerationHeuristics, type GenerationMeta, } from './geneHints.js';
107
+ export { validateWire, validateWireDeep, wireSchemaIssues, schemaProperties, type WireValidation, type WireSchemaIssue, } from './schemaGate.js';
108
+ export { ROUTING_TIERS, REASONING_LEVELS, TOOL_POLICY_SEVERITIES, GENERATION_SOURCES, CLAIM_KINDS, ENV_CLASSES, VERIFIER_DECISIONS, GENE_HINT_FIELDS, normalizeRoutingHint, normalizeToolPolicy, normalizeGenerationMeta, normalizeClaims, normalizeGeneScope, normalizeRuntimeProfile, normalizeVerifierProfile, stripGeneHints, type RoutingTier, type ReasoningLevel, type ToolPolicySeverity, type GenerationSource, type ClaimKind, type EnvClass, type VerifierDecision, type GeneRoutingHint, type GeneToolPolicy, type GeneGenerationHeuristics, type GenerationMeta, type GeneClaim, type GeneScope, type GeneRuntimeProfile, type GeneVerifierProfile, } from './geneHints.js';
@@ -1,3 +1,3 @@
1
1
  export { SCHEMA_VERSION, canonicalize, computeAssetId, verifyAssetId } from '@evomap/gep-sdk';
2
- export { validateWire, schemaProperties } from './schemaGate.js';
3
- export { ROUTING_TIERS, REASONING_LEVELS, TOOL_POLICY_SEVERITIES, GENERATION_SOURCES, GENE_HINT_FIELDS, normalizeRoutingHint, normalizeToolPolicy, normalizeGenerationMeta, stripGeneHints, } from './geneHints.js';
2
+ export { validateWire, validateWireDeep, wireSchemaIssues, schemaProperties, } from './schemaGate.js';
3
+ export { ROUTING_TIERS, REASONING_LEVELS, TOOL_POLICY_SEVERITIES, GENERATION_SOURCES, CLAIM_KINDS, ENV_CLASSES, VERIFIER_DECISIONS, GENE_HINT_FIELDS, normalizeRoutingHint, normalizeToolPolicy, normalizeGenerationMeta, normalizeClaims, normalizeGeneScope, normalizeRuntimeProfile, normalizeVerifierProfile, stripGeneHints, } from './geneHints.js';
@@ -2,10 +2,31 @@ export interface WireValidation {
2
2
  ok: boolean;
3
3
  errors: string[];
4
4
  }
5
+ /** One schema violation located at a concrete field, so a caller can decide what to do about THAT field.
6
+ * `validateWireDeep`'s message strings are deliberately stable/opaque; repair needs the location instead. */
7
+ export interface WireSchemaIssue {
8
+ /** Dotted path into the record (`constraints.forbidden_paths`); `''` for a record-level violation. */
9
+ path: string;
10
+ /** Ajv keyword that failed (`required`, `additionalProperties`, `minItems`, `pattern`, …). */
11
+ keyword: string;
12
+ /** Field named by a record-level violation: the missing required prop or the rejected extra prop. */
13
+ property?: string;
14
+ message: string;
15
+ }
5
16
  /**
6
17
  * 结构校验(required 齐 + additionalProperties:false 不许多字段). 轻量, 不做深类型校验(那是发版 CI conformance 的活).
7
18
  * 用途: 发 hub 前确认资产能被 gep-sdk schema 接受; v2-delta(proof_of_work/resolution_status)在 bump 前会在此暴露.
8
19
  */
9
20
  export declare function validateWire(asset: Record<string, unknown>): WireValidation;
21
+ /**
22
+ * Full Draft-07 runtime validation against the gep-sdk JSON Schema SSOT.
23
+ * Validation is observational: values are never coerced, defaulted, stripped, or otherwise mutated.
24
+ */
25
+ export declare function validateWireDeep(asset: Record<string, unknown>): WireValidation;
26
+ /**
27
+ * Every schema violation of `asset`, located by field. Same SSOT and same verdict as {@link validateWireDeep}
28
+ * (empty ⇔ ok) — this form exists for callers that must ACT on a specific field rather than only report.
29
+ */
30
+ export declare function wireSchemaIssues(asset: Record<string, unknown>): WireSchemaIssue[];
10
31
  /** schema 已声明的字段白名单(给上层判断哪些 v2-delta 尚未进 SDK). */
11
32
  export declare function schemaProperties(type: string): string[];