@wowok/agent-mcp 2.5.5 → 2.6.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.
Files changed (146) hide show
  1. package/README.md +5 -3
  2. package/dist/config/runtime.js +3 -6
  3. package/dist/extensions/capability-manifest.d.ts +125 -0
  4. package/dist/extensions/capability-manifest.js +594 -0
  5. package/dist/extensions/constraint-registry.d.ts +24 -0
  6. package/dist/extensions/constraint-registry.js +196 -0
  7. package/dist/extensions/index.d.ts +12 -0
  8. package/dist/extensions/index.js +6 -0
  9. package/dist/extensions/metric-registry.d.ts +26 -0
  10. package/dist/extensions/metric-registry.js +257 -0
  11. package/dist/extensions/mode-evaluator.d.ts +15 -0
  12. package/dist/extensions/mode-evaluator.js +170 -0
  13. package/dist/extensions/modes.d.ts +2 -0
  14. package/dist/extensions/modes.js +407 -0
  15. package/dist/extensions/registry.d.ts +48 -0
  16. package/dist/extensions/registry.js +629 -0
  17. package/dist/extensions/types.d.ts +218 -0
  18. package/dist/extensions/types.js +1 -0
  19. package/dist/harness/checkpoint.js +2 -2
  20. package/dist/knowledge/deployment-scanner.d.ts +3 -0
  21. package/dist/knowledge/deployment-scanner.js +64 -3
  22. package/dist/knowledge/flywheel-loop.js +2 -5
  23. package/dist/knowledge/guard-risk.d.ts +13 -0
  24. package/dist/knowledge/guard-risk.js +57 -0
  25. package/dist/knowledge/guard-templates.js +278 -0
  26. package/dist/knowledge/machine-templates.js +20 -1
  27. package/dist/knowledge/overrides-loader.js +2 -4
  28. package/dist/knowledge/progress-ledger.js +3 -0
  29. package/dist/knowledge/progress-translation.js +5 -1
  30. package/dist/knowledge/service-confirm.d.ts +14 -5
  31. package/dist/knowledge/service-confirm.js +116 -8
  32. package/dist/knowledge/tool-constraints.js +6 -2
  33. package/dist/loop-engineering/improve.js +2 -4
  34. package/dist/project/deployment-bridge.d.ts +5 -0
  35. package/dist/project/deployment-bridge.js +119 -0
  36. package/dist/project/deployment-doc.d.ts +3 -0
  37. package/dist/project/deployment-doc.js +72 -10
  38. package/dist/project/evaluation.d.ts +2 -0
  39. package/dist/project/evaluation.js +578 -86
  40. package/dist/project/graph-builder.d.ts +4 -1
  41. package/dist/project/graph-builder.js +141 -63
  42. package/dist/project/graph.d.ts +1 -0
  43. package/dist/project/handlers.d.ts +221 -5
  44. package/dist/project/handlers.js +933 -14
  45. package/dist/project/index.js +2 -6
  46. package/dist/project/project-store.js +2 -5
  47. package/dist/project/stage-gate.d.ts +4 -0
  48. package/dist/project/stage-gate.js +64 -5
  49. package/dist/project/task-tracker.d.ts +26 -0
  50. package/dist/project/task-tracker.js +78 -0
  51. package/dist/safety/preview.js +16 -0
  52. package/dist/schema/call/allocation.d.ts +16 -16
  53. package/dist/schema/call/base.d.ts +21 -13
  54. package/dist/schema/call/base.js +27 -6
  55. package/dist/schema/call/bridge.d.ts +5 -5
  56. package/dist/schema/call/bridge.js +3 -1
  57. package/dist/schema/call/demand.d.ts +23 -31
  58. package/dist/schema/call/guard.js +1 -1
  59. package/dist/schema/call/machine.d.ts +402 -376
  60. package/dist/schema/call/order.d.ts +149 -228
  61. package/dist/schema/call/order.js +7 -3
  62. package/dist/schema/call/payment.d.ts +183 -3
  63. package/dist/schema/call/payment.js +21 -3
  64. package/dist/schema/call/personal.d.ts +241 -52
  65. package/dist/schema/call/progress.d.ts +53 -61
  66. package/dist/schema/call/progress.js +18 -4
  67. package/dist/schema/call/repository.d.ts +23 -31
  68. package/dist/schema/call/semantic.d.ts +1 -1
  69. package/dist/schema/call/semantic.js +30 -1
  70. package/dist/schema/call/service.d.ts +95 -119
  71. package/dist/schema/call/service.js +22 -1
  72. package/dist/schema/common/index.d.ts +11 -2
  73. package/dist/schema/common/index.js +43 -14
  74. package/dist/schema/config/index.d.ts +12 -12
  75. package/dist/schema/local/index.d.ts +140 -143
  76. package/dist/schema/local/index.js +44 -23
  77. package/dist/schema/messenger/index.d.ts +290 -62
  78. package/dist/schema/messenger/index.js +2 -2
  79. package/dist/schema/operations.d.ts +680 -545
  80. package/dist/schema/operations.js +22 -0
  81. package/dist/schema/project/index.d.ts +2064 -84
  82. package/dist/schema/project/index.js +354 -12
  83. package/dist/schema/query/index.d.ts +715 -354
  84. package/dist/schema/query/index.js +164 -31
  85. package/dist/schema/schema-query/index.d.ts +15 -3
  86. package/dist/schema/schema-query/index.js +23 -5
  87. package/dist/schema/trust/index.d.ts +8 -8
  88. package/dist/schema/utils/node-parser.js +7 -4
  89. package/dist/schema-query/index.d.ts +7 -1
  90. package/dist/schema-query/index.js +204 -4
  91. package/dist/schemas/account_operation.output.json +14 -22
  92. package/dist/schemas/account_operation.schema.json +11 -25
  93. package/dist/schemas/bridge_operation.output.json +6 -0
  94. package/dist/schemas/bridge_operation.schema.json +1 -1
  95. package/dist/schemas/guard-templates.json +379 -0
  96. package/dist/schemas/guard2file.schema.json +1 -1
  97. package/dist/schemas/index.json +1 -1
  98. package/dist/schemas/local_info_operation.output.json +6 -0
  99. package/dist/schemas/local_mark_operation.output.json +7 -1
  100. package/dist/schemas/local_mark_operation.schema.json +1 -1
  101. package/dist/schemas/machineNode2file.schema.json +1 -1
  102. package/dist/schemas/messenger_operation.schema.json +10 -10
  103. package/dist/schemas/onchain_events.output.json +1 -1
  104. package/dist/schemas/onchain_operations.schema.json +348 -296
  105. package/dist/schemas/onchain_operations_allocation.schema.json +34 -25
  106. package/dist/schemas/onchain_operations_arbitration.schema.json +8 -8
  107. package/dist/schemas/onchain_operations_contact.schema.json +8 -8
  108. package/dist/schemas/onchain_operations_demand.schema.json +8 -8
  109. package/dist/schemas/onchain_operations_gen_passport.schema.json +14 -14
  110. package/dist/schemas/onchain_operations_gen_proof.schema.json +2 -2
  111. package/dist/schemas/onchain_operations_guard.schema.json +1 -1
  112. package/dist/schemas/onchain_operations_machine.schema.json +41 -33
  113. package/dist/schemas/onchain_operations_order.schema.json +71 -77
  114. package/dist/schemas/onchain_operations_payment.schema.json +141 -111
  115. package/dist/schemas/onchain_operations_permission.schema.json +2 -2
  116. package/dist/schemas/onchain_operations_personal.schema.json +7 -7
  117. package/dist/schemas/onchain_operations_progress.schema.json +8 -8
  118. package/dist/schemas/onchain_operations_proof.schema.json +7 -7
  119. package/dist/schemas/onchain_operations_repository.schema.json +8 -8
  120. package/dist/schemas/onchain_operations_reward.schema.json +10 -10
  121. package/dist/schemas/onchain_operations_service.schema.json +46 -35
  122. package/dist/schemas/onchain_operations_treasury.schema.json +8 -8
  123. package/dist/schemas/onchain_table_data.output.json +33 -25
  124. package/dist/schemas/onchain_table_data.schema.json +12 -12
  125. package/dist/schemas/project_operation.output.json +1352 -20
  126. package/dist/schemas/project_operation.schema.json +53 -4
  127. package/dist/schemas/query_toolkit.output.json +111 -82
  128. package/dist/schemas/query_toolkit.schema.json +9 -13
  129. package/dist/schemas/schema_query.output.json +7 -3
  130. package/dist/schemas/schema_query.schema.json +17 -3
  131. package/dist/telemetry/storage.js +2 -2
  132. package/dist/tools/handlers/local.js +20 -5
  133. package/dist/tools/handlers/onchain.js +36 -0
  134. package/dist/tools/handlers/project.js +72 -1
  135. package/dist/tools/handlers/query.js +27 -0
  136. package/dist/tools/handlers/schema-query.js +19 -0
  137. package/dist/tools/handlers/task-status.d.ts +170 -0
  138. package/dist/tools/handlers/task-status.js +55 -0
  139. package/dist/tools/handlers/wip.js +47 -1
  140. package/dist/tools/index.js +212 -8
  141. package/dist/tools/retry.d.ts +8 -0
  142. package/dist/tools/retry.js +85 -0
  143. package/dist/tools/wip-deploy-assist.d.ts +28 -0
  144. package/dist/tools/wip-deploy-assist.js +278 -0
  145. package/package.json +2 -2
  146. package/dist/schemas/guard-node-examples.md +0 -199
@@ -1,9 +1,9 @@
1
+ import { IndustryModeRegistry } from "../extensions/registry.js";
1
2
  const CRITICAL_BINDINGS = [
2
3
  { sourceType: "Service", targetType: "Machine", fieldName: "machine", critical: true },
3
4
  { sourceType: "Service", targetType: "Permission", fieldName: "permission", critical: true },
4
5
  { sourceType: "Service", targetType: "Guard", fieldName: "buy_guard", critical: false },
5
- { sourceType: "Service", targetType: "Treasury", fieldName: "compensation_fund", critical: false },
6
- { sourceType: "Service", targetType: "Allocation", fieldName: "order_allocators", critical: false },
6
+ { sourceType: "Service", targetType: "Allocation", fieldName: "order_allocators", critical: true },
7
7
  { sourceType: "Service", targetType: "Arbitration", fieldName: "arbitrations", critical: false },
8
8
  { sourceType: "Machine", targetType: "Permission", fieldName: "permission", critical: true },
9
9
  ];
@@ -11,21 +11,47 @@ const MERCHANT_REQUIRED_ITEMS = [
11
11
  { id: "R1", objectType: "Permission", fieldName: "", required: true, description: "Governance — who can manage the service" },
12
12
  { id: "R2", objectType: "Service", fieldName: "", required: true, description: "Core offering — the service itself" },
13
13
  { id: "R3", objectType: "Machine", fieldName: "machine", required: true, description: "Workflow — order processing pipeline" },
14
- { id: "R4", objectType: "Guard", fieldName: "buy_guard", required: true, description: "Purchase validation — guard on Service.buy()" },
15
- { id: "R5", objectType: "Allocation", fieldName: "order_allocators", required: true, description: "Order allocators — fund distribution rules" },
16
- { id: "R6", objectType: "Treasury", fieldName: "compensation_fund", required: true, description: "Compensation fund — buyer refund protection" },
17
- { id: "R7", objectType: "Arbitration", fieldName: "arbitrations", required: true, description: "Dispute resolution — arbitration configured" },
14
+ { id: "R4", objectType: "Guard", fieldName: "", required: true, description: "Purchase validation — Guard objects configured (binding to Service.buy_guard is optional)" },
15
+ { id: "R5", objectType: "Allocation", fieldName: "order_allocators", required: true, description: "Order allocators template — inline Allocators on Service (independent Allocation objects are created per-order)" },
16
+ { id: "R6", objectType: "Treasury", fieldName: "", required: true, description: "Compensation fund — independent Treasury object for buyer refund protection (industry-aware: optional for freelance)" },
17
+ { id: "R7", objectType: "Arbitration", fieldName: "arbitrations", required: true, description: "Dispute resolution — arbitration configured (required when compensation_fund > 0 per service.move:494)" },
18
18
  { id: "R8", objectType: "Contact", fieldName: "", required: true, description: "Customer communication — contact info" },
19
19
  { id: "R9", objectType: "Progress", fieldName: "", required: false, description: "Order tracking — progress nodes" },
20
20
  { id: "R10", objectType: "Reward", fieldName: "rewards", required: false, description: "Customer incentives — reward claims" },
21
21
  { id: "R11", objectType: "Repository", fieldName: "repositories", required: false, description: "Documentation — published data" },
22
22
  { id: "R12", objectType: "Demand", fieldName: "", required: false, description: "Market discovery — demand signals" },
23
23
  ];
24
+ function resolveRequiredItems(industry, compensationFundBalance = 0) {
25
+ let result = MERCHANT_REQUIRED_ITEMS;
26
+ if (industry && industry !== "general") {
27
+ let mode;
28
+ try {
29
+ mode = IndustryModeRegistry.Instance().getMode(industry);
30
+ }
31
+ catch {
32
+ }
33
+ if (mode) {
34
+ const requireFund = mode.risk_constraints?.require_compensation_fund ?? true;
35
+ if (!requireFund) {
36
+ result = MERCHANT_REQUIRED_ITEMS.map(item => {
37
+ if (item.id === "R6" || item.id === "R7") {
38
+ return { ...item, required: false };
39
+ }
40
+ return item;
41
+ });
42
+ }
43
+ }
44
+ }
45
+ if (compensationFundBalance > 0) {
46
+ result = result.map(item => item.id === "R7" ? { ...item, required: true } : item);
47
+ }
48
+ return result;
49
+ }
24
50
  const CONSUMER_DUE_DILIGENCE = [
25
51
  { id: "E1", check: "Service is published (bPublished=true)", severity: "critical", deduction: -30 },
26
52
  { id: "E2", check: "Service is not paused (bPaused=false)", severity: "warning", deduction: -20 },
27
53
  { id: "E3", check: "Machine has workflow nodes", severity: "warning", deduction: -15 },
28
- { id: "E4", check: "Service has buy_guard (purchase validation)", severity: "warning", deduction: -15 },
54
+ { id: "E4", check: "Service has buy_guard (purchase validation)", severity: "info", deduction: 0 },
29
55
  { id: "E5", check: "Service has compensation_fund (refund protection)", severity: "warning", deduction: -15 },
30
56
  { id: "E6", check: "Arbitration is configured (dispute resolution)", severity: "critical", deduction: -25 },
31
57
  { id: "E7", check: "Permission is present (governance)", severity: "warning", deduction: -10 },
@@ -34,11 +60,21 @@ const CONSUMER_DUE_DILIGENCE = [
34
60
  { id: "E10", check: "Reward is configured (customer incentives)", severity: "info", deduction: -3 },
35
61
  { id: "E11", check: "Service has description (offering clarity)", severity: "info", deduction: -5 },
36
62
  { id: "E12", check: "Registrar reputation is positive", severity: "warning", deduction: -10 },
37
- { id: "E13", check: "No critical findings in risk evaluation", severity: "critical", deduction: -20 },
38
63
  ];
39
64
  function clampScore(n) {
40
65
  return Math.max(0, Math.min(100, Math.round(n)));
41
66
  }
67
+ function shortTypeName(objectType) {
68
+ if (!objectType)
69
+ return "unknown";
70
+ const base = objectType.replace(/<.*>/, "").trim();
71
+ const segments = base.split("::");
72
+ const shortName = segments[segments.length - 1] || "unknown";
73
+ if (shortName.length > 0 && shortName === shortName.toLowerCase()) {
74
+ return shortName.charAt(0).toUpperCase() + shortName.slice(1);
75
+ }
76
+ return shortName;
77
+ }
42
78
  function parseCacheData(cached) {
43
79
  if (!cached)
44
80
  return null;
@@ -58,6 +94,104 @@ function countArrayField(data, field) {
58
94
  return v.length;
59
95
  return 0;
60
96
  }
97
+ export function getNumberField(data, field) {
98
+ if (!data)
99
+ return 0;
100
+ const v = data[field];
101
+ if (typeof v === "number" && Number.isFinite(v))
102
+ return v;
103
+ if (typeof v === "string") {
104
+ const n = Number(v);
105
+ if (Number.isFinite(n))
106
+ return n;
107
+ }
108
+ return 0;
109
+ }
110
+ export function getMachineNodeCount(data) {
111
+ if (!data)
112
+ return 0;
113
+ const nc = getNumberField(data, "node_count");
114
+ if (nc > 0)
115
+ return nc;
116
+ const arrLen = countArrayField(data, "nodes");
117
+ if (arrLen > 0)
118
+ return arrLen;
119
+ const nodesObj = data["nodes"];
120
+ if (nodesObj && typeof nodesObj === "object") {
121
+ const fieldsObj = nodesObj["fields"];
122
+ if (fieldsObj && typeof fieldsObj === "object") {
123
+ const sizeVal = getNumberField(fieldsObj, "size");
124
+ if (sizeVal > 0)
125
+ return sizeVal;
126
+ }
127
+ const directSize = getNumberField(nodesObj, "size");
128
+ if (directSize > 0)
129
+ return directSize;
130
+ }
131
+ return 0;
132
+ }
133
+ function getBalanceValue(data, field) {
134
+ if (!data)
135
+ return 0;
136
+ const v = data[field];
137
+ if (v == null)
138
+ return 0;
139
+ if (typeof v === "number" && Number.isFinite(v))
140
+ return v;
141
+ if (typeof v === "string") {
142
+ const n = Number(v);
143
+ if (Number.isFinite(n))
144
+ return n;
145
+ }
146
+ if (typeof v === "object") {
147
+ const obj = v;
148
+ const inner = obj.value ?? obj.fields;
149
+ if (typeof inner === "number" && Number.isFinite(inner))
150
+ return inner;
151
+ if (typeof inner === "string") {
152
+ const n = Number(inner);
153
+ if (Number.isFinite(n))
154
+ return n;
155
+ }
156
+ if (typeof inner === "object" && inner !== null) {
157
+ const innerObj = inner;
158
+ const val = innerObj.value;
159
+ if (typeof val === "number" && Number.isFinite(val))
160
+ return val;
161
+ if (typeof val === "string") {
162
+ const n = Number(val);
163
+ if (Number.isFinite(n))
164
+ return n;
165
+ }
166
+ }
167
+ }
168
+ return 0;
169
+ }
170
+ function getMaxSalePrice(data) {
171
+ if (!data)
172
+ return 0;
173
+ const sales = data.sales;
174
+ if (!Array.isArray(sales) || sales.length === 0)
175
+ return 0;
176
+ let max = 0;
177
+ for (const sale of sales) {
178
+ if (typeof sale !== "object" || sale === null)
179
+ continue;
180
+ const price = sale.price;
181
+ let n = 0;
182
+ if (typeof price === "number" && Number.isFinite(price)) {
183
+ n = price;
184
+ }
185
+ else if (typeof price === "string") {
186
+ const parsed = Number(price);
187
+ if (Number.isFinite(parsed))
188
+ n = parsed;
189
+ }
190
+ if (n > max)
191
+ max = n;
192
+ }
193
+ return max;
194
+ }
61
195
  function detectCircularRefs(edges) {
62
196
  const adj = new Map();
63
197
  for (const e of edges) {
@@ -71,14 +205,36 @@ function detectCircularRefs(edges) {
71
205
  const visited = new Set();
72
206
  const recursionStack = new Set();
73
207
  const path = [];
74
- const dfs = (node) => {
75
- visited.add(node);
76
- recursionStack.add(node);
77
- path.push(node);
78
- const neighbors = adj.get(node) ?? [];
79
- for (const neighbor of neighbors) {
208
+ for (const startNode of adj.keys()) {
209
+ if (visited.has(startNode))
210
+ continue;
211
+ const stack = [{
212
+ node: startNode,
213
+ nextNeighborIdx: 0,
214
+ neighbors: adj.get(startNode) ?? [],
215
+ }];
216
+ visited.add(startNode);
217
+ recursionStack.add(startNode);
218
+ path.push(startNode);
219
+ while (stack.length > 0) {
220
+ const frame = stack[stack.length - 1];
221
+ if (frame.nextNeighborIdx >= frame.neighbors.length) {
222
+ stack.pop();
223
+ path.pop();
224
+ recursionStack.delete(frame.node);
225
+ continue;
226
+ }
227
+ const neighbor = frame.neighbors[frame.nextNeighborIdx];
228
+ frame.nextNeighborIdx++;
80
229
  if (!visited.has(neighbor)) {
81
- dfs(neighbor);
230
+ visited.add(neighbor);
231
+ recursionStack.add(neighbor);
232
+ path.push(neighbor);
233
+ stack.push({
234
+ node: neighbor,
235
+ nextNeighborIdx: 0,
236
+ neighbors: adj.get(neighbor) ?? [],
237
+ });
82
238
  }
83
239
  else if (recursionStack.has(neighbor)) {
84
240
  const cycleStart = path.indexOf(neighbor);
@@ -86,12 +242,6 @@ function detectCircularRefs(edges) {
86
242
  cycles.push(cycle.join("→"));
87
243
  }
88
244
  }
89
- path.pop();
90
- recursionStack.delete(node);
91
- };
92
- for (const node of adj.keys()) {
93
- if (!visited.has(node))
94
- dfs(node);
95
245
  }
96
246
  return cycles;
97
247
  }
@@ -138,15 +288,171 @@ function buildBindingIndex(edges) {
138
288
  idx.set(key, new Set());
139
289
  idx.get(key).add(e.targetObject);
140
290
  }
291
+ for (const e of edges) {
292
+ if (e.edgeSource !== "potential")
293
+ continue;
294
+ if (!e.fieldName)
295
+ continue;
296
+ const key = `${e.sourceObject}#${e.fieldName}`;
297
+ if (!idx.has(key) || idx.get(key).size === 0) {
298
+ if (!idx.has(key))
299
+ idx.set(key, new Set());
300
+ idx.get(key).add(e.targetObject);
301
+ }
302
+ }
141
303
  return idx;
142
304
  }
305
+ function evaluateIndustryPattern(project, objects, objectCache, edges) {
306
+ const result = { strengths: [], findings: [], matched: false };
307
+ const industryName = project.industry;
308
+ if (!industryName || industryName === "general") {
309
+ return result;
310
+ }
311
+ let mode;
312
+ try {
313
+ mode = IndustryModeRegistry.Instance().getMode(industryName);
314
+ }
315
+ catch {
316
+ return result;
317
+ }
318
+ if (!mode)
319
+ return result;
320
+ const byType = new Map();
321
+ for (const obj of objects) {
322
+ const t = shortTypeName(obj.objectType);
323
+ if (!byType.has(t))
324
+ byType.set(t, []);
325
+ byType.get(t).push(obj);
326
+ }
327
+ const bindingIndex = buildBindingIndex(edges);
328
+ let matchCount = 0;
329
+ let totalChecks = 0;
330
+ const expectedNodes = mode.machine_shape;
331
+ if (expectedNodes.length > 0) {
332
+ totalChecks++;
333
+ const machines = byType.get("Machine") ?? [];
334
+ if (machines.length > 0) {
335
+ const machineObj = machines[0];
336
+ const cached = parseCacheData(objectCache.get(machineObj.objectAddress));
337
+ const nodeCount = getNumberField(cached, "node_count") || countArrayField(cached ?? {}, "nodes");
338
+ if (nodeCount > 0 && nodeCount >= expectedNodes.length) {
339
+ matchCount++;
340
+ result.strengths.push(`Industry pattern match: Machine has ${nodeCount} nodes, covering "${industryName}" mode's ${expectedNodes.length} expected node(s)`);
341
+ }
342
+ else if (nodeCount > 0) {
343
+ result.findings.push({
344
+ criterion: "industry_pattern",
345
+ severity: "info",
346
+ message: `Industry pattern: Machine has ${nodeCount} nodes, but "${industryName}" mode expects at least ${expectedNodes.length}`,
347
+ deduction: 0,
348
+ });
349
+ }
350
+ }
351
+ }
352
+ const expectedGuards = mode.guards;
353
+ if (expectedGuards.length > 0) {
354
+ totalChecks++;
355
+ const guards = byType.get("Guard") ?? [];
356
+ const minGuards = expectedGuards.length;
357
+ const maxGuards = expectedGuards.length * 2;
358
+ if (guards.length >= minGuards && guards.length <= maxGuards) {
359
+ matchCount++;
360
+ result.strengths.push(`Industry pattern match: ${guards.length} Guard(s) present, within "${industryName}" mode's expected range [${minGuards}-${maxGuards}]`);
361
+ }
362
+ else if (guards.length > 0 && guards.length < minGuards) {
363
+ result.findings.push({
364
+ criterion: "industry_pattern",
365
+ severity: "info",
366
+ message: `Industry pattern: ${guards.length} Guard(s) present, but "${industryName}" mode expects at least ${minGuards} (recommended range [${minGuards}-${maxGuards}])`,
367
+ deduction: 0,
368
+ });
369
+ }
370
+ else if (guards.length > maxGuards) {
371
+ matchCount++;
372
+ result.strengths.push(`Industry pattern match: ${guards.length} Guard(s) present, covering "${industryName}" mode's ${minGuards} expected guard(s)`);
373
+ result.findings.push({
374
+ criterion: "industry_pattern",
375
+ severity: "info",
376
+ message: `Industry pattern: ${guards.length} Guard(s) present, exceeds recommended max ${maxGuards}. Consider consolidating guards if some are redundant.`,
377
+ deduction: 0,
378
+ });
379
+ }
380
+ }
381
+ const expectedAllocStrategy = mode.allocator;
382
+ if (expectedAllocStrategy) {
383
+ totalChecks++;
384
+ const allocations = byType.get("Allocation") ?? [];
385
+ const services4Alloc = byType.get("Service") ?? [];
386
+ const serviceForAlloc = services4Alloc[0];
387
+ const hasOrderAllocators = serviceForAlloc
388
+ ? !!bindingIndex.get(`${serviceForAlloc.objectAddress}#order_allocators`)?.size
389
+ : false;
390
+ const expectsMultiple = mode.traits.multi_tier_allocation;
391
+ if (hasOrderAllocators) {
392
+ matchCount++;
393
+ if (allocations.length > 0) {
394
+ result.strengths.push(`Industry pattern match: Service.order_allocators bound + ${allocations.length} Allocation object(s) present (post-order) — matching "${industryName}" allocation pattern`);
395
+ }
396
+ else {
397
+ result.strengths.push(`Industry pattern match: Service.order_allocators template bound — matching "${industryName}" allocation pattern (Allocation objects created per-order)`);
398
+ }
399
+ }
400
+ else if (allocations.length > 0) {
401
+ matchCount++;
402
+ result.strengths.push(`Industry pattern match: ${allocations.length} Allocation object(s) present — matching "${industryName}" allocation pattern`);
403
+ }
404
+ else {
405
+ result.findings.push({
406
+ criterion: "industry_pattern",
407
+ severity: "info",
408
+ message: `Industry pattern: Service.order_allocators not bound and no Allocation objects — "${industryName}" mode expects ${expectsMultiple ? "multi-tier" : "single-tier"} allocation (Allocation objects are created per-order, so this is only a template-level gap)`,
409
+ deduction: 0,
410
+ });
411
+ }
412
+ }
413
+ const requireCompensationFund = mode.risk_constraints?.require_compensation_fund ?? false;
414
+ if (requireCompensationFund || mode.traits.deposit_required || mode.traits.trust_sensitivity !== "low") {
415
+ totalChecks++;
416
+ const treasuries = byType.get("Treasury") ?? [];
417
+ const services4Treas = byType.get("Service") ?? [];
418
+ const serviceForTreas = services4Treas[0];
419
+ const serviceDataForTreas = serviceForTreas
420
+ ? parseCacheData(objectCache.get(serviceForTreas.objectAddress))
421
+ : null;
422
+ const compensationBalance = serviceForTreas
423
+ ? getBalanceValue(serviceDataForTreas, "compensation_fund")
424
+ : 0;
425
+ if (treasuries.length > 0 || compensationBalance > 0) {
426
+ matchCount++;
427
+ const parts = [];
428
+ if (treasuries.length > 0)
429
+ parts.push(`${treasuries.length} Treasury object(s)`);
430
+ if (compensationBalance > 0)
431
+ parts.push(`compensation_fund balance ${compensationBalance}`);
432
+ result.strengths.push(`Industry pattern match: ${parts.join(" + ")} — matching "${industryName}" trust/deposit pattern`);
433
+ }
434
+ }
435
+ result.matched = totalChecks > 0 && matchCount / totalChecks >= 0.6;
436
+ if (result.matched) {
437
+ result.strengths.push(`Industry pattern: project structure matches "${industryName}" mode (${matchCount}/${totalChecks} checks passed)`);
438
+ }
439
+ else if (totalChecks > 0) {
440
+ result.findings.push({
441
+ criterion: "industry_pattern",
442
+ severity: "info",
443
+ message: `Industry pattern: project partially matches "${industryName}" mode (${matchCount}/${totalChecks} checks passed)`,
444
+ deduction: 0,
445
+ });
446
+ }
447
+ return result;
448
+ }
143
449
  function evaluateRisk(input) {
144
450
  const findings = [];
145
451
  const strengths = [];
146
452
  const { objects, edges, objectCache, project } = input;
147
453
  const byType = new Map();
148
454
  for (const obj of objects) {
149
- const t = obj.objectType ?? "unknown";
455
+ const t = shortTypeName(obj.objectType);
150
456
  if (!byType.has(t))
151
457
  byType.set(t, []);
152
458
  byType.get(t).push(obj);
@@ -155,19 +461,24 @@ function evaluateRisk(input) {
155
461
  const bindingIndex = buildBindingIndex(edges);
156
462
  let structuralScore = 100;
157
463
  const serviceObj = services[0];
464
+ const svcDataForStruct = serviceObj ? parseCacheData(objectCache.get(serviceObj.objectAddress)) : null;
465
+ const compensationBalanceForStruct = serviceObj ? getBalanceValue(svcDataForStruct, "compensation_fund") : 0;
158
466
  if (serviceObj) {
159
467
  for (const expected of CRITICAL_BINDINGS) {
160
468
  if (expected.sourceType !== "Service")
161
469
  continue;
470
+ const effectiveCritical = expected.fieldName === "arbitrations"
471
+ ? (compensationBalanceForStruct > 0 ? true : expected.critical)
472
+ : expected.critical;
162
473
  const key = `${serviceObj.objectAddress}#${expected.fieldName}`;
163
474
  const bindings = bindingIndex.get(key);
164
475
  if (!bindings || bindings.size === 0) {
165
- const deduction = expected.critical ? -25 : -10;
476
+ const deduction = effectiveCritical ? -25 : -10;
166
477
  structuralScore += deduction;
167
478
  findings.push({
168
479
  criterion: "structural_risk",
169
- severity: expected.critical ? "critical" : "warning",
170
- message: `Service missing ${expected.fieldName} binding (expected ${expected.targetType})`,
480
+ severity: effectiveCritical ? "critical" : "warning",
481
+ message: `Service missing ${expected.fieldName} binding (expected ${expected.targetType})${expected.fieldName === "arbitrations" ? (compensationBalanceForStruct > 0 ? " — required by contract when compensation_fund > 0 (service.move:494)" : " — optional when compensation_fund is 0") : ""}`,
171
482
  deduction,
172
483
  });
173
484
  }
@@ -188,27 +499,72 @@ function evaluateRisk(input) {
188
499
  structuralScore = clampScore(structuralScore);
189
500
  let fundScore = 100;
190
501
  const treasuries = byType.get("Treasury") ?? [];
191
- if (treasuries.length === 0) {
192
- fundScore -= 30;
193
- findings.push({
194
- criterion: "fund_safety",
195
- severity: "warning",
196
- message: "No Treasury object — no compensation fund for refunds",
197
- deduction: -30,
198
- });
199
- }
200
- else {
201
- strengths.push(`${treasuries.length} Treasury object(s) present`);
502
+ const serviceData = serviceObj ? parseCacheData(objectCache.get(serviceObj.objectAddress)) : null;
503
+ const compensationBalance = serviceObj ? getBalanceValue(serviceData, "compensation_fund") : 0;
504
+ let industryRequiresFund = true;
505
+ if (project.industry && project.industry !== "general") {
506
+ try {
507
+ const mode = IndustryModeRegistry.Instance().getMode(project.industry);
508
+ if (mode) {
509
+ industryRequiresFund = mode.risk_constraints?.require_compensation_fund ?? true;
510
+ }
511
+ }
512
+ catch { }
202
513
  }
203
- if (serviceObj) {
204
- const cfKey = `${serviceObj.objectAddress}#compensation_fund`;
205
- if (!bindingIndex.get(cfKey)?.size) {
206
- fundScore -= 20;
514
+ if (treasuries.length === 0 && compensationBalance === 0) {
515
+ if (industryRequiresFund) {
516
+ fundScore -= 30;
207
517
  findings.push({
208
518
  criterion: "fund_safety",
209
519
  severity: "warning",
210
- message: "Service compensation_fund not bound — buyer refunds unprotected",
211
- deduction: -20,
520
+ message: "No Treasury object and Service.compensation_fund is empty — no refund fund for buyers",
521
+ deduction: -30,
522
+ });
523
+ }
524
+ else {
525
+ fundScore -= 10;
526
+ findings.push({
527
+ criterion: "fund_safety",
528
+ severity: "info",
529
+ message: `No Treasury/compensation_fund — industry "${project.industry}" does not require refund fund (optional)`,
530
+ deduction: -10,
531
+ });
532
+ }
533
+ }
534
+ else {
535
+ if (treasuries.length > 0) {
536
+ strengths.push(`${treasuries.length} Treasury object(s) present — independent fund holder`);
537
+ }
538
+ if (compensationBalance > 0) {
539
+ strengths.push(`Service.compensation_fund has ${compensationBalance} units — inline refund fund active`);
540
+ const maxSalePrice = getMaxSalePrice(serviceData);
541
+ if (maxSalePrice > 0) {
542
+ const requiredThreshold = 5 * maxSalePrice;
543
+ if (compensationBalance < requiredThreshold) {
544
+ fundScore -= 10;
545
+ findings.push({
546
+ criterion: "fund_safety",
547
+ severity: "warning",
548
+ message: `Service.compensation_fund balance (${compensationBalance}) is less than 5× the max order amount (${maxSalePrice} → threshold ${requiredThreshold}). Refund coverage may be insufficient — top up via service.compensation_fund_add to avoid arbitration rulings exceeding the fund.`,
549
+ deduction: -10,
550
+ });
551
+ }
552
+ else {
553
+ findings.push({
554
+ criterion: "fund_safety",
555
+ severity: "info",
556
+ message: `Service.compensation_fund balance (${compensationBalance}) covers 5× the max order amount (${maxSalePrice}). Fund is sufficient for refund protection.`,
557
+ deduction: 0,
558
+ });
559
+ }
560
+ }
561
+ }
562
+ else {
563
+ findings.push({
564
+ criterion: "fund_safety",
565
+ severity: "info",
566
+ message: "Treasury present but Service.compensation_fund balance is 0 — consider depositing refund fund",
567
+ deduction: -5,
212
568
  });
213
569
  }
214
570
  }
@@ -267,18 +623,27 @@ function evaluateRisk(input) {
267
623
  if (serviceObj) {
268
624
  const data = parseCacheData(objectCache.get(serviceObj.objectAddress));
269
625
  if (data && !isAddress(data.um)) {
270
- governanceScore -= 15;
626
+ governanceScore -= 5;
271
627
  findings.push({
272
628
  criterion: "governance_risk",
273
- severity: "warning",
274
- message: "Service has no UM (manager) — cannot be managed on-chain",
275
- deduction: -15,
629
+ severity: "info",
630
+ message: "Service has no UM (manager) — UM is optional; set via um_set if management delegation needed",
631
+ deduction: -5,
276
632
  });
277
633
  }
278
634
  }
279
635
  governanceScore = clampScore(governanceScore);
280
636
  let coherenceScore = 100;
281
- const objectAddresses = new Set(objects.map(o => o.objectAddress));
637
+ const objectAddresses = new Set();
638
+ for (const o of objects) {
639
+ if (o.objectAddress)
640
+ objectAddresses.add(o.objectAddress);
641
+ if (o.objectName) {
642
+ objectAddresses.add(o.objectName);
643
+ const shortType = shortTypeName(o.objectType).toLowerCase();
644
+ objectAddresses.add(`${shortType}:${o.objectName}`);
645
+ }
646
+ }
282
647
  let danglingCount = 0;
283
648
  for (const e of edges) {
284
649
  if (e.edgeSource === "potential")
@@ -340,7 +705,7 @@ function evaluateTrust(input) {
340
705
  const { objects, edges, objectCache, reputation, project } = input;
341
706
  const byType = new Map();
342
707
  for (const obj of objects) {
343
- const t = obj.objectType ?? "unknown";
708
+ const t = shortTypeName(obj.objectType);
344
709
  if (!byType.has(t))
345
710
  byType.set(t, []);
346
711
  byType.get(t).push(obj);
@@ -416,15 +781,10 @@ function evaluateTrust(input) {
416
781
  const bgKey = `${services[0].objectAddress}#buy_guard`;
417
782
  if (bindingIndex.get(bgKey)?.size) {
418
783
  guardScore = clampScore(guardScore + 15);
419
- strengths.push("Service has buy_guard — purchase validation active");
784
+ strengths.push("Service has buy_guard bound — purchase validation active");
420
785
  }
421
- else {
422
- findings.push({
423
- criterion: "guard_quality",
424
- severity: "warning",
425
- message: "Service buy_guard not bound — unvalidated purchases",
426
- deduction: -15,
427
- });
786
+ else if (guards.length > 0) {
787
+ strengths.push("Guard objects present (buy_guard binding optional)");
428
788
  }
429
789
  }
430
790
  guardScore = clampScore(guardScore);
@@ -484,14 +844,16 @@ function evaluateTrust(input) {
484
844
  case "E3":
485
845
  passed = (byType.get("Machine") ?? []).some(m => {
486
846
  const d = parseCacheData(objectCache.get(m.objectAddress));
487
- return d && (countArrayField(d, "nodes") > 0);
847
+ return d && (getNumberField(d, "node_count") > 0 || countArrayField(d, "nodes") > 0);
488
848
  });
489
849
  break;
490
850
  case "E4":
491
- passed = !!bindingIndex2.get(`${serviceObj2.objectAddress}#buy_guard`)?.size;
851
+ passed = !!bindingIndex2.get(`${serviceObj2.objectAddress}#buy_guard`)?.size
852
+ || (byType.get("Guard") ?? []).length > 0;
492
853
  break;
493
854
  case "E5":
494
- passed = !!bindingIndex2.get(`${serviceObj2.objectAddress}#compensation_fund`)?.size;
855
+ passed = getBalanceValue(svcData, "compensation_fund") > 0
856
+ || (byType.get("Treasury") ?? []).length > 0;
495
857
  break;
496
858
  case "E6":
497
859
  passed = (byType.get("Arbitration") ?? []).length > 0;
@@ -517,20 +879,32 @@ function evaluateTrust(input) {
517
879
  passed = !!rep && rep.likes >= rep.dislikes;
518
880
  }
519
881
  break;
520
- case "E13":
521
- passed = true;
522
- break;
523
882
  }
524
883
  if (passed) {
525
884
  diligencePassed.push(check.id);
526
885
  }
527
886
  else {
528
- diligenceScore += check.deduction;
887
+ let effectiveDeduction = check.deduction;
888
+ let effectiveSeverity = check.severity;
889
+ if (check.id === "E5" && project.industry && project.industry !== "general") {
890
+ try {
891
+ const mode = IndustryModeRegistry.Instance().getMode(project.industry);
892
+ if (mode && mode.risk_constraints?.require_compensation_fund === false) {
893
+ effectiveDeduction = -3;
894
+ effectiveSeverity = "info";
895
+ }
896
+ }
897
+ catch { }
898
+ }
899
+ diligenceScore += effectiveDeduction;
900
+ const detailSuffix = check.id === "E5" && effectiveDeduction !== check.deduction
901
+ ? " (industry does not require compensation_fund — reduced deduction)"
902
+ : "";
529
903
  findings.push({
530
904
  criterion: "consumer_diligence",
531
- severity: check.severity,
532
- message: `${check.id}: ${check.check} — FAILED`,
533
- deduction: check.deduction,
905
+ severity: effectiveSeverity,
906
+ message: `${check.id}: ${check.check} — FAIL: condition not met${detailSuffix} [severity: ${effectiveSeverity}]`,
907
+ deduction: effectiveDeduction,
534
908
  });
535
909
  }
536
910
  }
@@ -578,14 +952,19 @@ function evaluateCompleteness(input) {
578
952
  const { objects, edges, objectCache, project } = input;
579
953
  const byType = new Map();
580
954
  for (const obj of objects) {
581
- const t = obj.objectType ?? "unknown";
955
+ const t = shortTypeName(obj.objectType);
582
956
  if (!byType.has(t))
583
957
  byType.set(t, []);
584
958
  byType.get(t).push(obj);
585
959
  }
586
960
  const services = byType.get("Service") ?? [];
587
961
  const bindingIndex = buildBindingIndex(edges);
588
- const requiredItems = MERCHANT_REQUIRED_ITEMS;
962
+ const svcObjForRequiredItems = services[0];
963
+ const svcDataForRequiredItems = svcObjForRequiredItems
964
+ ? parseCacheData(objectCache.get(svcObjForRequiredItems.objectAddress))
965
+ : null;
966
+ const compensationBalanceForItems = getBalanceValue(svcDataForRequiredItems, "compensation_fund");
967
+ const requiredItems = resolveRequiredItems(project.industry ?? undefined, compensationBalanceForItems);
589
968
  const requiredCount = requiredItems.filter(r => r.required).length;
590
969
  const optionalItems = requiredItems.filter(r => !r.required);
591
970
  let requiredMet = 0;
@@ -643,23 +1022,28 @@ function evaluateCompleteness(input) {
643
1022
  let bindingScore = 100;
644
1023
  if (services[0]) {
645
1024
  const serviceAddr = services[0].objectAddress;
1025
+ const svcDataForBind = parseCacheData(objectCache.get(serviceAddr));
1026
+ const compensationBalanceForBind = getBalanceValue(svcDataForBind, "compensation_fund");
646
1027
  let boundCount = 0;
647
1028
  let totalCount = 0;
648
1029
  for (const expected of CRITICAL_BINDINGS) {
649
1030
  if (expected.sourceType !== "Service")
650
1031
  continue;
651
1032
  totalCount++;
1033
+ const effectiveCritical = expected.fieldName === "arbitrations"
1034
+ ? (compensationBalanceForBind > 0 ? true : expected.critical)
1035
+ : expected.critical;
652
1036
  const key = `${serviceAddr}#${expected.fieldName}`;
653
1037
  if (bindingIndex.get(key)?.size) {
654
1038
  boundCount++;
655
1039
  }
656
1040
  else {
657
- const deduction = expected.critical ? -20 : -8;
1041
+ const deduction = effectiveCritical ? -20 : -8;
658
1042
  bindingScore += deduction;
659
1043
  findings.push({
660
1044
  criterion: "binding_completeness",
661
- severity: expected.critical ? "critical" : "warning",
662
- message: `Service.${expected.fieldName} not bound (expected ${expected.targetType})`,
1045
+ severity: effectiveCritical ? "critical" : "warning",
1046
+ message: `Service.${expected.fieldName} not bound (expected ${expected.targetType})${expected.fieldName === "arbitrations" ? (compensationBalanceForBind > 0 ? " — required by contract when compensation_fund > 0" : " — optional when compensation_fund is 0") : ""}`,
663
1047
  deduction,
664
1048
  });
665
1049
  }
@@ -681,19 +1065,19 @@ function evaluateCompleteness(input) {
681
1065
  let workflowScore = 80;
682
1066
  const machines = byType.get("Machine") ?? [];
683
1067
  if (machines.length === 0) {
684
- workflowScore -= 30;
1068
+ workflowScore -= 20;
685
1069
  findings.push({
686
1070
  criterion: "workflow_rationality",
687
- severity: "warning",
688
- message: "No Machine object — no workflow defined",
689
- deduction: -30,
1071
+ severity: "info",
1072
+ message: "No Machine object — bind one before publishing (deploy-time requirement)",
1073
+ deduction: -20,
690
1074
  });
691
1075
  }
692
1076
  else {
693
1077
  for (const m of machines) {
694
1078
  const data = parseCacheData(objectCache.get(m.objectAddress));
695
1079
  if (data) {
696
- const nodeCount = countArrayField(data, "nodes") || countArrayField(data, "node_count");
1080
+ const nodeCount = getNumberField(data, "node_count") || countArrayField(data, "nodes");
697
1081
  if (nodeCount > 0) {
698
1082
  strengths.push(`Machine has ${nodeCount} node(s)`);
699
1083
  }
@@ -709,7 +1093,16 @@ function evaluateCompleteness(input) {
709
1093
  }
710
1094
  }
711
1095
  }
712
- const objectAddresses = new Set(objects.map(o => o.objectAddress));
1096
+ const objectAddresses = new Set();
1097
+ for (const o of objects) {
1098
+ if (o.objectAddress)
1099
+ objectAddresses.add(o.objectAddress);
1100
+ if (o.objectName) {
1101
+ objectAddresses.add(o.objectName);
1102
+ const shortType = shortTypeName(o.objectType).toLowerCase();
1103
+ objectAddresses.add(`${shortType}:${o.objectName}`);
1104
+ }
1105
+ }
713
1106
  let danglingCount = 0;
714
1107
  for (const e of edges) {
715
1108
  if (e.edgeSource === "potential")
@@ -735,10 +1128,26 @@ function evaluateCompleteness(input) {
735
1128
  if (published) {
736
1129
  strengths.push("Service already published — deployment complete");
737
1130
  readinessScore = 100;
1131
+ const machineAddr = data.machine;
1132
+ if (typeof machineAddr === "string" && machineAddr.startsWith("0x")) {
1133
+ const machineData = parseCacheData(objectCache.get(machineAddr));
1134
+ if (machineData && machineData.bPublished === false) {
1135
+ readinessScore -= 10;
1136
+ findings.push({
1137
+ criterion: "deployment_readiness",
1138
+ severity: "info",
1139
+ message: `Bound Machine ${machineAddr.slice(0, 8)} is not published — order_progress will fail (machine.move E_NOT_PUBLISHED)`,
1140
+ deduction: -10,
1141
+ });
1142
+ }
1143
+ }
738
1144
  }
739
1145
  else {
740
1146
  const hasMachine = bindingIndex.get(`${services[0].objectAddress}#machine`)?.size;
741
1147
  const hasPermission = bindingIndex.get(`${services[0].objectAddress}#permission`)?.size;
1148
+ const hasOrderAllocators = bindingIndex.get(`${services[0].objectAddress}#order_allocators`)?.size;
1149
+ const compensationBalanceForReady = getBalanceValue(data, "compensation_fund");
1150
+ const hasArbitrations = bindingIndex.get(`${services[0].objectAddress}#arbitrations`)?.size;
742
1151
  if (!hasMachine) {
743
1152
  readinessScore -= 30;
744
1153
  findings.push({
@@ -757,8 +1166,31 @@ function evaluateCompleteness(input) {
757
1166
  deduction: -30,
758
1167
  });
759
1168
  }
760
- if (hasMachine && hasPermission) {
761
- strengths.push("Service ready to publish (Machine + Permission bound)");
1169
+ if (!hasOrderAllocators) {
1170
+ readinessScore -= 30;
1171
+ findings.push({
1172
+ criterion: "deployment_readiness",
1173
+ severity: "critical",
1174
+ message: "Service has no order_allocators — cannot publish (service.move:493 E_NO_ALLOCATOR)",
1175
+ deduction: -30,
1176
+ });
1177
+ }
1178
+ if (compensationBalanceForReady > 0 && !hasArbitrations) {
1179
+ readinessScore -= 25;
1180
+ findings.push({
1181
+ criterion: "deployment_readiness",
1182
+ severity: "critical",
1183
+ message: `Service has compensation_fund (${compensationBalanceForReady}) but no arbitrations — cannot publish (service.move:495 E_ARBITRATION_NOT_SET_WITH_COMPENSATION_FUND)`,
1184
+ deduction: -25,
1185
+ });
1186
+ }
1187
+ if (hasMachine && hasPermission && hasOrderAllocators) {
1188
+ if (compensationBalanceForReady > 0 && hasArbitrations) {
1189
+ strengths.push("Service ready to publish (Machine + Permission + order_allocators + arbitrations bound)");
1190
+ }
1191
+ else if (compensationBalanceForReady === 0) {
1192
+ strengths.push("Service ready to publish (Machine + Permission + order_allocators bound; arbitrations optional when compensation_fund is 0)");
1193
+ }
762
1194
  }
763
1195
  }
764
1196
  }
@@ -781,6 +1213,9 @@ function evaluateCompleteness(input) {
781
1213
  : overall >= 80
782
1214
  ? `Complete project (score ${overall}/100). Ready for deployment.`
783
1215
  : `Partially complete (score ${overall}/100). ${findings.length} gap(s) to address.`;
1216
+ const industryPattern = evaluateIndustryPattern(project, objects, objectCache, edges);
1217
+ strengths.push(...industryPattern.strengths);
1218
+ findings.push(...industryPattern.findings);
784
1219
  return {
785
1220
  evaluationType: "completeness",
786
1221
  score: overall,
@@ -792,7 +1227,7 @@ function evaluateCompleteness(input) {
792
1227
  evaluatedAt: Date.now(),
793
1228
  };
794
1229
  }
795
- function evaluateWorthBuyingStub(input, llmPrompt) {
1230
+ function evaluateWorthBuyingStub(_input, llmPrompt) {
796
1231
  return {
797
1232
  evaluationType: "worth_buying",
798
1233
  score: 0,
@@ -805,7 +1240,7 @@ function evaluateWorthBuyingStub(input, llmPrompt) {
805
1240
  evaluatedAt: Date.now(),
806
1241
  };
807
1242
  }
808
- function evaluateValueStub(input, llmPrompt) {
1243
+ function evaluateValueStub(_input, llmPrompt) {
809
1244
  return {
810
1245
  evaluationType: "value",
811
1246
  score: 0,
@@ -819,21 +1254,78 @@ function evaluateValueStub(input, llmPrompt) {
819
1254
  };
820
1255
  }
821
1256
  export function runEvaluation(input, evaluationType, llmPrompt) {
1257
+ const filtered = filterTemplateObjects(input);
822
1258
  switch (evaluationType) {
823
1259
  case "risk":
824
- return evaluateRisk(input);
1260
+ return evaluateRisk(filtered);
825
1261
  case "trust":
826
- return evaluateTrust(input);
1262
+ return evaluateTrust(filtered);
827
1263
  case "completeness":
828
- return evaluateCompleteness(input);
1264
+ return evaluateCompleteness(filtered);
829
1265
  case "worth_buying":
830
- return evaluateWorthBuyingStub(input, llmPrompt);
1266
+ return evaluateWorthBuyingStub(filtered, llmPrompt);
831
1267
  case "value":
832
- return evaluateValueStub(input, llmPrompt);
1268
+ return evaluateValueStub(filtered, llmPrompt);
833
1269
  default:
834
1270
  throw new Error(`Unknown evaluation type: ${evaluationType}`);
835
1271
  }
836
1272
  }
1273
+ function filterTemplateObjects(input) {
1274
+ const isDraftAddr = (addr) => {
1275
+ if (!addr)
1276
+ return true;
1277
+ return addr.startsWith("draft:");
1278
+ };
1279
+ const isDraftObject = (o) => {
1280
+ if (isDraftAddr(o.objectAddress))
1281
+ return true;
1282
+ const meta = o.metadata;
1283
+ return !!(meta && meta.status === "draft");
1284
+ };
1285
+ const draftObjects = [];
1286
+ const realObjects = [];
1287
+ for (const o of input.objects) {
1288
+ if (isDraftObject(o)) {
1289
+ draftObjects.push(o);
1290
+ }
1291
+ else {
1292
+ realObjects.push(o);
1293
+ }
1294
+ }
1295
+ const realIds = new Set();
1296
+ for (const o of realObjects) {
1297
+ if (o.objectAddress)
1298
+ realIds.add(o.objectAddress);
1299
+ if (o.objectName) {
1300
+ realIds.add(o.objectName);
1301
+ const shortType = shortTypeName(o.objectType).toLowerCase();
1302
+ realIds.add(`${shortType}:${o.objectName}`);
1303
+ }
1304
+ }
1305
+ const draftIds = new Set();
1306
+ for (const o of draftObjects) {
1307
+ if (o.objectAddress)
1308
+ draftIds.add(o.objectAddress);
1309
+ if (o.objectName) {
1310
+ draftIds.add(o.objectName);
1311
+ const shortType = shortTypeName(o.objectType).toLowerCase();
1312
+ draftIds.add(`${shortType}:${o.objectName}`);
1313
+ }
1314
+ }
1315
+ const realEdges = input.edges.filter((e) => {
1316
+ const meta = e.metadata;
1317
+ if (meta && meta.blueprint === true)
1318
+ return false;
1319
+ const sourceIsDraft = isDraftAddr(e.sourceObject) || draftIds.has(e.sourceObject);
1320
+ const targetIsDraft = isDraftAddr(e.targetObject) || draftIds.has(e.targetObject);
1321
+ return !sourceIsDraft && !targetIsDraft;
1322
+ });
1323
+ return {
1324
+ ...input,
1325
+ objects: realObjects,
1326
+ edges: realEdges,
1327
+ };
1328
+ }
837
1329
  export function compareProjects(entries, evaluationType) {
838
1330
  const ranking = [...entries].sort((a, b) => {
839
1331
  if (a.score === null && b.score === null)