@wowok/agent-mcp 2.3.16 → 2.4.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 (136) hide show
  1. package/dist/customer/index.d.ts +9 -0
  2. package/dist/customer/index.js +9 -0
  3. package/dist/customer/industry-risks.d.ts +4 -0
  4. package/dist/customer/industry-risks.js +45 -31
  5. package/dist/customer/order-monitor.js +57 -57
  6. package/dist/customer/order-strategy.js +89 -89
  7. package/dist/customer/post-purchase.js +97 -97
  8. package/dist/customer/reminder-system.js +26 -26
  9. package/dist/customer/risk-assessment.js +46 -46
  10. package/dist/customer/types.d.ts +4 -4
  11. package/dist/customer/types.js +4 -4
  12. package/dist/customer/user-preferences.d.ts +3 -0
  13. package/dist/customer/user-preferences.js +59 -50
  14. package/dist/experience/intent-distill.js +6 -6
  15. package/dist/experience/realtime-feedback.js +17 -0
  16. package/dist/index.js +360 -273
  17. package/dist/knowledge/acquisition-flywheel.d.ts +3 -0
  18. package/dist/knowledge/acquisition-flywheel.js +73 -64
  19. package/dist/knowledge/arbitration-trust.js +10 -10
  20. package/dist/knowledge/demand-matching.js +8 -8
  21. package/dist/knowledge/dynamic-pricing.js +18 -18
  22. package/dist/knowledge/flywheel-loop.js +11 -11
  23. package/dist/knowledge/glossary.js +22 -22
  24. package/dist/knowledge/guard-ledger.d.ts +19 -0
  25. package/dist/knowledge/guard-ledger.js +246 -0
  26. package/dist/knowledge/guard-lint.d.ts +76 -0
  27. package/dist/knowledge/guard-lint.js +590 -0
  28. package/dist/knowledge/guard-puzzle.d.ts +188 -0
  29. package/dist/knowledge/guard-puzzle.js +804 -0
  30. package/dist/knowledge/guard-risk.d.ts +67 -0
  31. package/dist/knowledge/guard-risk.js +1046 -0
  32. package/dist/knowledge/guard-templates.d.ts +37 -0
  33. package/dist/knowledge/guard-templates.js +329 -0
  34. package/dist/knowledge/guard-translation.d.ts +58 -0
  35. package/dist/knowledge/guard-translation.js +1118 -0
  36. package/dist/knowledge/index.d.ts +17 -0
  37. package/dist/knowledge/index.js +17 -0
  38. package/dist/knowledge/industry-evolution.js +29 -29
  39. package/dist/knowledge/industry-generalizer.js +52 -52
  40. package/dist/knowledge/industry-registry.d.ts +1 -2
  41. package/dist/knowledge/industry-registry.js +43 -36
  42. package/dist/knowledge/intent-metrics.js +67 -67
  43. package/dist/knowledge/process-model.js +80 -80
  44. package/dist/knowledge/reputation-rules.js +9 -9
  45. package/dist/knowledge/reward-templates.js +51 -51
  46. package/dist/knowledge/safety-rules.js +63 -2
  47. package/dist/knowledge/tool-constraints.js +17 -11
  48. package/dist/knowledge/trust-metrics.js +26 -26
  49. package/dist/safety/confirm-gate.d.ts +4 -2
  50. package/dist/safety/confirm-gate.js +48 -4
  51. package/dist/schema/call/allocation.d.ts +24 -14
  52. package/dist/schema/call/arbitration.d.ts +142 -132
  53. package/dist/schema/call/base.d.ts +901 -43
  54. package/dist/schema/call/base.js +77 -13
  55. package/dist/schema/call/bridge-handler.js +15 -2
  56. package/dist/schema/call/bridge.d.ts +795 -27
  57. package/dist/schema/call/bridge.js +37 -0
  58. package/dist/schema/call/contact.d.ts +10 -0
  59. package/dist/schema/call/demand.d.ts +94 -84
  60. package/dist/schema/call/guard.d.ts +229 -46
  61. package/dist/schema/call/guard.js +50 -0
  62. package/dist/schema/call/handler.js +46 -14
  63. package/dist/schema/call/machine.d.ts +158 -138
  64. package/dist/schema/call/order.d.ts +10 -0
  65. package/dist/schema/call/payment.d.ts +10 -0
  66. package/dist/schema/call/permission.d.ts +314 -304
  67. package/dist/schema/call/personal.d.ts +10 -0
  68. package/dist/schema/call/progress.d.ts +10 -0
  69. package/dist/schema/call/proof.d.ts +20 -0
  70. package/dist/schema/call/repository.d.ts +32 -22
  71. package/dist/schema/call/reward.d.ts +10 -0
  72. package/dist/schema/call/semantic.d.ts +9 -2
  73. package/dist/schema/call/semantic.js +617 -25
  74. package/dist/schema/call/service.d.ts +20 -10
  75. package/dist/schema/call/treasury.d.ts +10 -0
  76. package/dist/schema/config/index.d.ts +18 -0
  77. package/dist/schema/config/index.js +17 -0
  78. package/dist/schema/index.d.ts +6 -0
  79. package/dist/schema/index.js +5 -0
  80. package/dist/schema/local/index.d.ts +9 -9
  81. package/dist/schema/local/index.js +9 -0
  82. package/dist/schema/local/wip.d.ts +39 -19
  83. package/dist/schema/local/wip.js +5 -5
  84. package/dist/schema/messenger/index.d.ts +376 -55
  85. package/dist/schema/messenger/index.js +19 -19
  86. package/dist/schema/operations.d.ts +1881 -681
  87. package/dist/schema/operations.js +91 -96
  88. package/dist/schema/project/index.d.ts +21 -0
  89. package/dist/schema/project/index.js +32 -0
  90. package/dist/schema/query/index.d.ts +1074 -168
  91. package/dist/schema/query/index.js +8 -8
  92. package/dist/schema/schema-query/index.d.ts +33 -0
  93. package/dist/schema/schema-query/index.js +36 -0
  94. package/dist/schema/schema-version.d.ts +25 -0
  95. package/dist/schema/schema-version.js +76 -0
  96. package/dist/schema/trust/index.d.ts +407 -0
  97. package/dist/schema/trust/index.js +113 -0
  98. package/dist/schema/utils/guard-parser.js +4 -4
  99. package/dist/schema/utils/node-parser.js +14 -14
  100. package/dist/schemas/bridge_operation.output.json +233 -9
  101. package/dist/schemas/bridge_operation.schema.json +67 -8
  102. package/dist/schemas/config_operation.output.json +18 -0
  103. package/dist/schemas/config_operation.schema.json +34 -0
  104. package/dist/schemas/guard-node-schema.json +82 -0
  105. package/dist/schemas/guard2file.schema.json +8 -0
  106. package/dist/schemas/index.json +19 -1
  107. package/dist/schemas/machineNode2file.schema.json +8 -0
  108. package/dist/schemas/messenger_operation.output.json +236 -10
  109. package/dist/schemas/onchain_events.output.json +718 -0
  110. package/dist/schemas/onchain_operations.output.json +286 -11
  111. package/dist/schemas/onchain_operations.schema.json +19 -16
  112. package/dist/schemas/onchain_operations_allocation.schema.json +8 -0
  113. package/dist/schemas/onchain_operations_arbitration.schema.json +8 -0
  114. package/dist/schemas/onchain_operations_contact.schema.json +8 -0
  115. package/dist/schemas/onchain_operations_demand.schema.json +8 -0
  116. package/dist/schemas/onchain_operations_gen_passport.schema.json +16 -0
  117. package/dist/schemas/onchain_operations_guard.schema.json +11 -16
  118. package/dist/schemas/onchain_operations_machine.schema.json +8 -0
  119. package/dist/schemas/onchain_operations_order.schema.json +8 -0
  120. package/dist/schemas/onchain_operations_payment.schema.json +8 -0
  121. package/dist/schemas/onchain_operations_permission.schema.json +8 -0
  122. package/dist/schemas/onchain_operations_personal.schema.json +8 -0
  123. package/dist/schemas/onchain_operations_progress.schema.json +8 -0
  124. package/dist/schemas/onchain_operations_repository.schema.json +8 -0
  125. package/dist/schemas/onchain_operations_reward.schema.json +8 -0
  126. package/dist/schemas/onchain_operations_service.schema.json +8 -0
  127. package/dist/schemas/onchain_operations_treasury.schema.json +8 -0
  128. package/dist/schemas/onchain_table_data.output.json +718 -0
  129. package/dist/schemas/project_operation.output.json +18 -0
  130. package/dist/schemas/project_operation.schema.json +42 -0
  131. package/dist/schemas/query_toolkit.schema.json +360 -368
  132. package/dist/schemas/schema_query.schema.json +6 -3
  133. package/dist/schemas/trust_score.output.json +327 -0
  134. package/dist/schemas/trust_score.schema.json +46 -0
  135. package/dist/schemas/wip_file.output.json +24 -1
  136. package/package.json +2 -2
@@ -0,0 +1,1046 @@
1
+ function rootStr(ctx) {
2
+ return JSON.stringify(ctx.root).toLowerCase();
3
+ }
4
+ function hasSignerCheck(ctx) {
5
+ return JSON.stringify(ctx.root).includes('"Signer"');
6
+ }
7
+ function hasClockCheck(ctx) {
8
+ return JSON.stringify(ctx.root).includes('"Clock"');
9
+ }
10
+ function hasGuardSelfRef(ctx) {
11
+ return JSON.stringify(ctx.root).includes('"Guard"');
12
+ }
13
+ function hasWitness(root) {
14
+ const str = JSON.stringify(root);
15
+ return str.includes('"convert_witness"');
16
+ }
17
+ function queriesRepository(ctx) {
18
+ return rootStr(ctx).includes('repository');
19
+ }
20
+ function queriesProgress(ctx) {
21
+ return rootStr(ctx).includes('progress');
22
+ }
23
+ function extractWitnessCodes(root) {
24
+ const codes = [];
25
+ const str = JSON.stringify(root);
26
+ const matches = str.matchAll(/"convert_witness"\s*:\s*(\d+)/g);
27
+ for (const m of matches) {
28
+ const code = parseInt(m[1], 10);
29
+ if (code >= 100 && code <= 108)
30
+ codes.push(code);
31
+ }
32
+ return codes;
33
+ }
34
+ const RISK_RULES = [
35
+ {
36
+ id: "R-C1-01",
37
+ data_source_class: "type1_onchain_constant",
38
+ trigger: "Guard table contains Address constants with b_submission=false; values may change after Guard rebuild",
39
+ check: (ctx) => {
40
+ const constAddrEntries = ctx.table.filter((e) => !e.b_submission && e.value_type === "Address" && e.value);
41
+ if (constAddrEntries.length === 0)
42
+ return null;
43
+ return {
44
+ id: "R-C1-01",
45
+ data_source_class: "type1_onchain_constant",
46
+ level: "low",
47
+ category: "data_source_trust",
48
+ title: "Constant object addresses may be inconsistent after Guard rebuild",
49
+ description: `Guard table contains ${constAddrEntries.length} Address constants (b_submission=false).` +
50
+ "Guard is immutable, but if a future Guard rebuild is needed (e.g. to fix logic), the new Guard's table constant addresses may differ from the old version." +
51
+ "Objects referencing the old Guard (Machine/Service, etc.) will not auto-update, leading to constant address inconsistency.",
52
+ affected_stakeholders: ["provider"],
53
+ scenario: "Guard iteration: after rebuild, constant addresses change but references still point to the old Guard",
54
+ mitigation: "1) After Guard rebuild, update all references (Machine forward guard, Service buy_guard, etc.);" +
55
+ "2) Use guard2file to export a backup and record constant-address-to-semantics mappings;" +
56
+ "3) Document constant-address changes in the migration notes",
57
+ evidence: `Constant Address entries: ${constAddrEntries.map((e) => `#${e.identifier}=${e.value}`).join(", ")}`,
58
+ };
59
+ },
60
+ },
61
+ {
62
+ id: "R-C1-02",
63
+ data_source_class: "type1_onchain_constant",
64
+ trigger: "Guard table contains EntityRegistrar(0xaab) or EntityLinker(0xaaa) system address constants",
65
+ check: (ctx) => {
66
+ const sysAddrEntries = ctx.table.filter((e) => !e.b_submission &&
67
+ e.value_type === "Address" &&
68
+ typeof e.value === "string" &&
69
+ (e.value.toLowerCase() === "0xaab" || e.value.toLowerCase() === "0xaaa"));
70
+ if (sysAddrEntries.length === 0)
71
+ return null;
72
+ const wrong = sysAddrEntries.find((e) => (e.value === "0xaab" && e.name && !e.name.toLowerCase().includes("registrar")) ||
73
+ (e.value === "0xaaa" && e.name && !e.name.toLowerCase().includes("linker")));
74
+ return {
75
+ id: "R-C1-02",
76
+ data_source_class: "type1_onchain_constant",
77
+ level: wrong ? "medium" : "info",
78
+ category: "data_source_trust",
79
+ title: wrong
80
+ ? "EntityRegistrar/EntityLinker system address name annotation suspected to be wrong"
81
+ : "Guard uses EntityRegistrar/EntityLinker system address constants",
82
+ description: "EntityRegistrar (0xaab) and EntityLinker (0xaaa) are fixed WoWok protocol system addresses." +
83
+ (wrong
84
+ ? "Detected name annotation does not match the address (e.g. 0xaab not annotated as registrar), which may cause semantic misunderstanding."
85
+ : "Address is correct, but ensure the name annotation is clear to avoid later maintenance confusion."),
86
+ affected_stakeholders: ["provider"],
87
+ scenario: "System address misuse: incorrect 0xaab/0xaaa name annotation causes query target confusion",
88
+ mitigation: "1) Confirm 0xaab corresponds to EntityRegistrar (entity registrar);" +
89
+ "2) Confirm 0xaaa corresponds to EntityLinker (entity linker);" +
90
+ "3) The table entry name should clearly indicate the system address purpose",
91
+ evidence: `System address entries: ${sysAddrEntries.map((e) => `#${e.identifier}=${e.value}(${e.name})`).join(", ")}`,
92
+ };
93
+ },
94
+ },
95
+ {
96
+ id: "R-C1-03",
97
+ data_source_class: "type1_onchain_constant",
98
+ trigger: "Guard queries Repository data without verifying writer permissions",
99
+ check: (ctx) => {
100
+ if (!queriesRepository(ctx))
101
+ return null;
102
+ if (hasSignerCheck(ctx))
103
+ return null;
104
+ return {
105
+ id: "R-C1-03",
106
+ data_source_class: "type1_onchain_constant",
107
+ level: "high",
108
+ category: "data_source_trust",
109
+ title: "Repository data source does not verify writer permissions",
110
+ description: "Guard queries Repository data but does not verify who has permission to write to that Repository." +
111
+ "A malicious writer can manipulate Repository data to deceive the Guard. As a Type1 constant object, " +
112
+ "the Repository's address is immutable, but its internal data can be modified by authorized writers.",
113
+ affected_stakeholders: ["customer", "provider"],
114
+ scenario: "Data source manipulation: attacker writes false data so Guard passes",
115
+ mitigation: "1) Restrict writer permissions in the Repository write_guard;" +
116
+ "2) Add context(Signer) in the current Guard to verify writer identity;" +
117
+ "3) Use multi-point data source cross-validation",
118
+ };
119
+ },
120
+ },
121
+ {
122
+ id: "R-C2-01",
123
+ data_source_class: "type2_witness_derived",
124
+ trigger: "Guard uses multi-hop witness (106/107/108: Arb→Progress/Machine/Service) to derive target object",
125
+ check: (ctx) => {
126
+ const codes = extractWitnessCodes(ctx.root);
127
+ const multiHop = codes.filter((c) => [106, 107, 108].includes(c));
128
+ if (multiHop.length === 0)
129
+ return null;
130
+ const witnessNames = {
131
+ 106: "Arb→Progress (two hops: arb.order → order.progress)",
132
+ 107: "Arb→Machine (two hops: arb.order → order.machine)",
133
+ 108: "Arb→Service (two hops: arb.order → order.service)",
134
+ };
135
+ return {
136
+ id: "R-C2-01",
137
+ data_source_class: "type2_witness_derived",
138
+ level: "medium",
139
+ category: "data_source_trust",
140
+ title: "Multi-hop witness chain derivation may break",
141
+ description: `Guard uses multi-hop witness [${multiHop.join(", ")}] to derive target object.` +
142
+ "Multi-hop witness (e.g. Arb→Progress requires reading arb.order then order.progress) requires intermediate objects to exist and fields to be set." +
143
+ "If an intermediate object does not exist (e.g. Arb's order field is empty) or the relationship chain breaks, witness derivation fails." +
144
+ "In the WoWok protocol this usually returns empty or 0, potentially causing unexpected Guard behavior.\n" +
145
+ multiHop.map((c) => ` - ${c}: ${witnessNames[c]}`).join("\n"),
146
+ affected_stakeholders: ["customer", "provider", "arbitrator"],
147
+ scenario: "Witness break: intermediate object missing causes derivation failure and unexpected Guard behavior",
148
+ mitigation: "1) Confirm the Arb object's order field is properly set (Arb is bound to Order at creation);" +
149
+ "2) Add null checks for derived results in Guard logic;" +
150
+ "3) Prefer single-hop witness (100-105) to reduce derivation chain length;" +
151
+ "4) Test the edge case where Arb is not associated with an Order",
152
+ evidence: `Multi-hop witness codes: ${multiHop.join(", ")}`,
153
+ };
154
+ },
155
+ },
156
+ {
157
+ id: "R-C2-02",
158
+ data_source_class: "type2_witness_derived",
159
+ trigger: "Guard uses witness but source object's object_type may not match the witness source type",
160
+ check: (ctx) => {
161
+ const codes = extractWitnessCodes(ctx.root);
162
+ if (codes.length === 0)
163
+ return null;
164
+ const witnessSourceTypes = {
165
+ 100: "Order", 101: "Order", 102: "Order",
166
+ 103: "Progress",
167
+ 104: "Arb", 105: "Arb", 106: "Arb", 107: "Arb", 108: "Arb",
168
+ };
169
+ const rootStr = JSON.stringify(ctx.root);
170
+ const mismatches = [];
171
+ for (const code of codes) {
172
+ const expectedSource = witnessSourceTypes[code];
173
+ if (!expectedSource)
174
+ continue;
175
+ const pattern1 = new RegExp(`"identifier"\\s*:\\s*(\\d+)\\s*,\\s*"convert_witness"\\s*:\\s*${code}`, "g");
176
+ const pattern2 = new RegExp(`"convert_witness"\\s*:\\s*${code}\\s*,\\s*"identifier"\\s*:\\s*(\\d+)`, "g");
177
+ const foundIds = new Set();
178
+ let m;
179
+ while ((m = pattern1.exec(rootStr)) !== null) {
180
+ foundIds.add(parseInt(m[1], 10));
181
+ }
182
+ while ((m = pattern2.exec(rootStr)) !== null) {
183
+ foundIds.add(parseInt(m[1], 10));
184
+ }
185
+ for (const id of foundIds) {
186
+ const entry = ctx.table.find((e) => e.identifier === id);
187
+ if (entry?.object_type && entry.object_type !== expectedSource) {
188
+ mismatches.push(`witness ${code}(${expectedSource}→?) references #${id} object_type=${entry.object_type}`);
189
+ }
190
+ }
191
+ }
192
+ if (mismatches.length === 0)
193
+ return null;
194
+ return {
195
+ id: "R-C2-02",
196
+ data_source_class: "type2_witness_derived",
197
+ level: "low",
198
+ category: "data_source_trust",
199
+ title: "witness source object object_type may not match the witness source type",
200
+ description: "Guard uses witness derivation, but the source object's object_type in table is inconsistent with the witness expected source type.\n" +
201
+ mismatches.map((mm) => ` - ${mm}`).join("\n") +
202
+ "\nNote: object_type is an auxiliary annotation field on table entries; it is not strictly validated at on-chain creation." +
203
+ "However, wrong annotations cause semantic misunderstanding and maintenance difficulty.",
204
+ affected_stakeholders: ["provider"],
205
+ scenario: "Type annotation mismatch: witness source type annotation is wrong, causing semantic confusion",
206
+ mitigation: "1) Fix the table entry's object_type field to match the witness source type;" +
207
+ "2) witness 100-102 source type is Order; 103 is Progress; 104-108 is Arb;" +
208
+ "3) Use wowok_buildin_info(info='guard instructions') to query the full witness definition",
209
+ evidence: mismatches.join("; "),
210
+ };
211
+ },
212
+ },
213
+ {
214
+ id: "R-C2-03",
215
+ data_source_class: "type2_witness_derived",
216
+ trigger: "Guard queries Progress status without verifying Machine publish state",
217
+ check: (ctx) => {
218
+ if (!queriesProgress(ctx))
219
+ return null;
220
+ if (!hasWitness(ctx.root))
221
+ return null;
222
+ if (ctx.scene?.host_object !== "Machine")
223
+ return null;
224
+ return {
225
+ id: "R-C2-03",
226
+ data_source_class: "type2_witness_derived",
227
+ level: "medium",
228
+ category: "data_source_trust",
229
+ title: "Progress data depends on Machine immutability",
230
+ description: "Guard queries Progress status via witness, and the Guard is bound to a Machine." +
231
+ "If the Machine is not published (bPublished=false), the Provider can modify the Machine node structure, " +
232
+ "causing node names validated by the Guard to become invalid or be renamed. Progress's current node name, node time, etc. " +
233
+ "all depend on the Machine's node definitions.",
234
+ affected_stakeholders: ["customer"],
235
+ scenario: "Provider modifies Machine node names to invalidate Guard verification",
236
+ mitigation: "1) Ensure the Machine is published (bPublished=true) before binding the Guard;" +
237
+ "2) Query the Machine.bPublished field in the Guard to verify;" +
238
+ "3) Use node IDs instead of node names for comparison",
239
+ };
240
+ },
241
+ },
242
+ {
243
+ id: "R-C2-04",
244
+ data_source_class: "type2_witness_derived",
245
+ trigger: "Guard uses witness query and the query parameter requires type conversion (e.g. Address → U64 timestamp key)",
246
+ check: (ctx) => {
247
+ if (!hasWitness(ctx.root))
248
+ return null;
249
+ const str = rootStr(ctx);
250
+ const hasTypeConversion = str.includes("convert_number_address") ||
251
+ str.includes("convert_address_number") ||
252
+ str.includes("convert_u256") ||
253
+ str.includes("convert_string");
254
+ const queriesRepo = str.includes("repository") && str.includes('"query"');
255
+ const queriesProgressHistory = str.includes("progress_history") && str.includes('"query"');
256
+ if (!queriesRepo && !queriesProgressHistory)
257
+ return null;
258
+ return {
259
+ id: "R-C2-04",
260
+ data_source_class: "type2_witness_derived",
261
+ level: "medium",
262
+ category: "data_source_trust",
263
+ title: "witness query parameter requires type translation (missing will cause type mismatch or wrong comparison)",
264
+ description: "Guard queries object fields via witness, but the query parameter type may not match the type declared in table.\n" +
265
+ "Typical scenarios:\n" +
266
+ " - Repository.data query: the key may be of Address type (vector<u8> address representation in Move), " +
267
+ "but the actual semantics is a U64 timestamp, requiring convert_number_address translation\n" +
268
+ " - Progress.history query: Forward ID may need to be converted from String to Address\n" +
269
+ " - Order field query: some ID fields may be stored as Address but need U256 for comparison\n" +
270
+ (hasTypeConversion
271
+ ? "\nThe current Guard already uses type conversion nodes, but ensure the conversion direction is correct."
272
+ : "\nWarning: no type conversion node detected in the current Guard; parameter type mismatch risk may exist."),
273
+ affected_stakeholders: ["provider", "customer"],
274
+ scenario: "Query parameter type does not match the parameters type defined by GUARDQUERY, causing creation failure or runtime comparison error",
275
+ mitigation: "1) Query GUARDQUERY to confirm the parameters type and return type of each query instruction;\n" +
276
+ "2) If table declares Address but the query needs U64, use convert_number_address to translate;\n" +
277
+ "3) Use wowok_buildin_info info='guard instructions' to verify parameter types;\n" +
278
+ "4) Verify type compatibility via schema_query before creation",
279
+ evidence: hasTypeConversion ? "Type conversion node in use" : "No type conversion node detected",
280
+ };
281
+ },
282
+ },
283
+ {
284
+ id: "R-C3-01",
285
+ data_source_class: "type3_submitted_object",
286
+ trigger: "Guard depends on submitted data but does not verify signer identity (no Signer check=high; with Signer check=info downgrade)",
287
+ check: (ctx) => {
288
+ const hasSubmission = ctx.table.some((e) => e.b_submission);
289
+ if (!hasSubmission)
290
+ return null;
291
+ if (ctx.scene?.binding_field === "voting_guard")
292
+ return null;
293
+ if (!hasSignerCheck(ctx)) {
294
+ if (ctx.scene?.id === "machine_forward_guard") {
295
+ return {
296
+ id: "R-C3-01",
297
+ data_source_class: "type3_submitted_object",
298
+ level: "medium",
299
+ category: "submission_forgery",
300
+ title: "Submitted data not bound to signer identity (Forward scenario implicitly verified by permissionIndex)",
301
+ description: "Guard accepts runtime-submitted data (b_submission=true), and root does not explicitly verify Signer." +
302
+ "This Guard is used for Machine Forward; Forward's permissionIndex/namedOperator already implicitly verifies operator identity, " +
303
+ "so the Signer binding risk is reduced. But permissionIndex only verifies 'operator has permission', " +
304
+ "not 'submitted data belongs to operator' — for example, a merchant holding permissionIndex can still submit someone else's credentials.",
305
+ affected_stakeholders: ["customer", "provider"],
306
+ scenario: "In-permission forgery: an authorized operator submits someone else's data (e.g. someone else's Merkle Root)",
307
+ mitigation: "1) If the submitted data should belong to the operator (e.g. the operator's address), it is still recommended to add context(Signer) binding;" +
308
+ "2) If the submitted data is a public credential (e.g. Merkle Root string), the current risk is acceptable;" +
309
+ "3) Use retained_submission to retain submitted data for later audit",
310
+ };
311
+ }
312
+ return {
313
+ id: "R-C3-01",
314
+ data_source_class: "type3_submitted_object",
315
+ level: "high",
316
+ category: "submission_forgery",
317
+ title: "Submitted data not bound to signer identity",
318
+ description: "Guard accepts runtime-submitted data (b_submission=true), but does not verify whether the submitter is the current transaction signer." +
319
+ "An attacker can submit someone else's data (e.g. someone else's address, someone else's credentials) to pass the Guard." +
320
+ "Type3 submitted objects are isomorphic with Type1 at the native layer (TYPE_QUERY+TYPE_CONSTANT), " +
321
+ "the only difference being that the value is injected by submission, so identity must be bound via logical constraints.",
322
+ affected_stakeholders: ["customer", "provider"],
323
+ scenario: "Identity forgery: attacker submits someone else's address to impersonate an authorized user",
324
+ mitigation: "1) Add context(Signer) binding with the submitted data for verification;" +
325
+ "2) Use vec_contains_address to verify the signer is in the whitelist;" +
326
+ "3) Use Passport credentials instead of bare address submission",
327
+ };
328
+ }
329
+ return {
330
+ id: "R-C3-01",
331
+ data_source_class: "type3_submitted_object",
332
+ level: "info",
333
+ category: "submission_forgery",
334
+ title: "Submitted data is indirectly bound via context(Signer) (confirm the binding direction is correct)",
335
+ description: "Guard accepts runtime-submitted data, and the root subtree contains a context(Signer) check, " +
336
+ "forming an indirect binding between submitted data and signer, reducing forgery risk." +
337
+ "But manual confirmation is needed: the constant compared with context(Signer) is the correct role (e.g. Provider address rather than Customer address), " +
338
+ "and the submitted data should indeed be provided by that signer. See R-C4-01 Signer direction risk.",
339
+ affected_stakeholders: ["customer", "provider"],
340
+ scenario: "Indirect binding to confirm: whether the Signer check direction matches the submitted data ownership",
341
+ mitigation: "1) Confirm context(Signer) is compared with the correct table constant (Provider address rather than Customer address);" +
342
+ "2) Confirm the source role of the submitted data matches the Signer check;" +
343
+ "3) For stricter binding, use query to verify the submitter's on-chain identity",
344
+ };
345
+ },
346
+ },
347
+ {
348
+ id: "R-C3-02",
349
+ data_source_class: "type3_submitted_object",
350
+ trigger: "voting_guard weight comes from submitted data without verifying source",
351
+ check: (ctx) => {
352
+ if (ctx.scene?.binding_field !== "voting_guard")
353
+ return null;
354
+ const numericEntries = ctx.table.filter((e) => e.b_submission &&
355
+ ["U8", "U16", "U32", "U64", "U128", "U256"].includes(e.value_type));
356
+ if (numericEntries.length === 0)
357
+ return null;
358
+ return {
359
+ id: "R-C3-02",
360
+ data_source_class: "type3_submitted_object",
361
+ level: "critical",
362
+ category: "submission_forgery",
363
+ title: "Voting weight comes from user submission and may be forged",
364
+ description: "voting_guard weight data comes from table entries with b_submission=true (Type3 submitted values)." +
365
+ "If the weight is not verified through EntityRegistrar or other trusted sources, " +
366
+ "a voter can submit arbitrarily high weights to manipulate the voting result." +
367
+ "Type3 submitted values are only validated by type byte (value[0]) at the native layer; value range and source are not checked.",
368
+ affected_stakeholders: ["arbitrator"],
369
+ scenario: "Weight forgery: voters submit fake high scores to manipulate the arbitration result",
370
+ mitigation: "1) Weights should be queried from EntityRegistrar rather than submitted by users;" +
371
+ "2) Use query(entity.records) to obtain on-chain registered reputation scores;" +
372
+ "3) Verify in the Guard that the submitted weight matches the on-chain record",
373
+ evidence: `Submitted numeric entries: ${numericEntries.map((e) => `#${e.identifier}(${e.value_type})`).join(", ")}`,
374
+ };
375
+ },
376
+ },
377
+ {
378
+ id: "R-C3-03",
379
+ data_source_class: "type3_submitted_object",
380
+ trigger: "Guard contains Address entries with b_submission=true; the runtime submitted object type may not match expectations",
381
+ check: (ctx) => {
382
+ const submittedAddr = ctx.table.filter((e) => e.b_submission && e.value_type === "Address");
383
+ if (submittedAddr.length === 0)
384
+ return null;
385
+ const noType = submittedAddr.filter((e) => !e.object_type);
386
+ const hasQuery = rootStr(ctx).includes('"query"');
387
+ if (!hasQuery)
388
+ return null;
389
+ return {
390
+ id: "R-C3-03",
391
+ data_source_class: "type3_submitted_object",
392
+ level: noType.length > 0 ? "medium" : "low",
393
+ category: "submission_forgery",
394
+ title: noType.length > 0
395
+ ? "Submitted object missing object_type annotation; runtime type validation relies on native inference"
396
+ : "Submitted object type validation relies on runtime native inference",
397
+ description: "Guard contains " + submittedAddr.length + " Address entries with b_submission=true (Type3 submitted objects)." +
398
+ "The native layer (passport.rs#parse_table_items) only checks the value[0] type byte for submission; " +
399
+ "object_type is derived at runtime by wobject_type and does not strictly validate the actual submitted object type.\n" +
400
+ (noType.length > 0
401
+ ? `Warning: ${noType.length} entries are missing object_type annotation, semantics are unclear.`
402
+ : "object_type is annotated, but still confirm the annotation matches what the query expects."),
403
+ affected_stakeholders: ["customer", "provider"],
404
+ scenario: "Type mismatch: submitting a wrong-typed object causes query to return unexpected values",
405
+ mitigation: "1) Annotate object_type for all Address entries with b_submission=true;" +
406
+ "2) object_type should match the object type expected by the query instruction;" +
407
+ "3) Indirectly verify the object type via query results in Guard logic (e.g. query order.amount to verify it is an Order)",
408
+ evidence: noType.length > 0
409
+ ? `Missing object_type: ${noType.map((e) => `#${e.identifier}`).join(", ")}`
410
+ : `Annotated: ${submittedAddr.map((e) => `#${e.identifier}=${e.object_type}`).join(", ")}`,
411
+ };
412
+ },
413
+ },
414
+ {
415
+ id: "R-C3-04",
416
+ data_source_class: "type3_submitted_object",
417
+ trigger: "Repository write_guard does not verify id_from_submission type",
418
+ check: (ctx) => {
419
+ if (ctx.scene?.binding_field !== "write_guard")
420
+ return null;
421
+ return {
422
+ id: "R-C3-04",
423
+ data_source_class: "type3_submitted_object",
424
+ level: "high",
425
+ category: "binding_risk",
426
+ title: "Repository write_guard must verify id_from_submission type",
427
+ description: "The table entry referenced by Repository write_guard's id_from_submission must be of Address type (Type3 submitted object)." +
428
+ "The entry referenced by data_from_submission must match the Repository value_type." +
429
+ "Type mismatch will cause write failure or data corruption. The write_guard submission contains both id and data parts; " +
430
+ "the native layer distinguishes them by op_code, but value types must match the table declaration.",
431
+ affected_stakeholders: ["provider"],
432
+ scenario: "Type mismatch: write failure or data corruption",
433
+ mitigation: "1) Confirm the entry referenced by id_from_submission has value_type=Address;" +
434
+ "2) Confirm the entry referenced by data_from_submission has value_type matching the Repository;" +
435
+ "3) Cover write scenarios in gen_passport tests",
436
+ };
437
+ },
438
+ },
439
+ {
440
+ id: "R-C4-01",
441
+ data_source_class: "type4_system_context",
442
+ trigger: "Guard contains context(Signer) check; need to confirm comparison direction (== vs !=) and compared object role",
443
+ check: (ctx) => {
444
+ if (!hasSignerCheck(ctx))
445
+ return null;
446
+ const rootStrRaw = JSON.stringify(ctx.root);
447
+ const hasEqual = rootStrRaw.includes('"logic_equal"');
448
+ const hasNotEqual = rootStrRaw.includes('"logic_not_equal"');
449
+ return {
450
+ id: "R-C4-01",
451
+ data_source_class: "type4_system_context",
452
+ level: "medium",
453
+ category: "system_context_risk",
454
+ title: "Signer check direction needs manual confirmation (comparison operator and role match)",
455
+ description: "Guard contains a context(Signer) check. Signer is a Type4 system context, " +
456
+ "from TransactionContext.sender() (transaction initiator address).\n" +
457
+ `Detected comparison: ${hasEqual ? "logic_equal(==)" : ""} ${hasNotEqual ? "logic_not_equal(!=)" : ""}\n` +
458
+ "Manual confirmation required:\n" +
459
+ " 1) Whether the comparison direction is correct: use == for identity verification (Signer == authorized address), use != for exclusion (Signer != blacklist address)\n" +
460
+ " 2) Whether the compared object role is correct: buy_guard should compare the Customer address, Forward.guard may compare the Provider address\n" +
461
+ " 3) Wrong direction causes reverse effect: == blacklist address would only allow blacklisted users",
462
+ affected_stakeholders: ["customer", "provider"],
463
+ scenario: "Wrong direction: Signer == blacklist address would only allow blacklisted users",
464
+ mitigation: "1) Confirm logic_equal is used for identity verification (Signer == authorized address);" +
465
+ "2) Confirm logic_not_equal is used for exclusion (Signer != blacklist address);" +
466
+ "3) Confirm the compared table constant is the address of the correct role;" +
467
+ "4) Cover both expected-pass and expected-fail scenarios in gen_passport tests",
468
+ evidence: `Comparison: ${hasEqual ? "==" : ""} ${hasNotEqual ? "!=" : ""}`,
469
+ };
470
+ },
471
+ },
472
+ {
473
+ id: "R-C4-02",
474
+ data_source_class: "type4_system_context",
475
+ trigger: "Guard uses context(Clock) for precise boundary time-lock comparison",
476
+ check: (ctx) => {
477
+ if (!hasClockCheck(ctx))
478
+ return null;
479
+ const str = rootStr(ctx);
480
+ const hasGreaterOrEqual = str.includes("logic_as_u256_greater_or_equal");
481
+ const hasGreater = str.includes("logic_as_u256_greater");
482
+ if (!hasGreaterOrEqual && !hasGreater)
483
+ return null;
484
+ return {
485
+ id: "R-C4-02",
486
+ data_source_class: "type4_system_context",
487
+ level: "low",
488
+ category: "system_context_risk",
489
+ title: "Clock time-lock should have tolerance to avoid boundary invalidation from validator block-time variance",
490
+ description: "Guard uses context(Clock) for time-lock comparison. Clock comes from the timestamp_ms field (U64 millisecond timestamp) of system shared object 0x6.\n" +
491
+ "The Sui on-chain timestamp is produced by validator consensus and has a slight deviation from real time (usually < 1 second), " +
492
+ "and block-time variance may cause timestamp jumps. Using precise boundaries (>= or ==) may cause:\n" +
493
+ " - The time-lock expiration transaction is packaged exactly at the moment but fails due to slight timestamp deviation\n" +
494
+ " - Or conversely, slight deviation causes the time-lock to pass early\n" +
495
+ "It is recommended to use > instead of >=, or add a small tolerance constant.",
496
+ affected_stakeholders: ["customer", "provider"],
497
+ scenario: "Timestamp variance: validator block-time deviation causes boundary transactions to fail or pass early",
498
+ mitigation: "1) Use logic_as_u256_greater (>) instead of greater_or_equal (>=) for expiration judgment;" +
499
+ "2) Or add a small tolerance constant (e.g. 1000ms) in calc_number_add;" +
500
+ "3) Time-locks should not rely on second-level precision; reserve minute-level tolerance;" +
501
+ "4) Design timeout Forward nodes in the Machine as a fallback",
502
+ evidence: `Comparison: ${hasGreaterOrEqual ? ">=" : ""} ${hasGreater ? ">" : ""}`,
503
+ };
504
+ },
505
+ },
506
+ {
507
+ id: "R-C4-03",
508
+ data_source_class: "type4_system_context",
509
+ trigger: "Guard uses context(Guard) self-reference",
510
+ check: (ctx) => {
511
+ if (!hasGuardSelfRef(ctx))
512
+ return null;
513
+ return {
514
+ id: "R-C4-03",
515
+ data_source_class: "type4_system_context",
516
+ level: "info",
517
+ category: "system_context_risk",
518
+ title: "Guard uses context(Guard) self-reference (rare scenario, needs special explanation)",
519
+ description: "Guard contains a context(Guard) node. Guard is a Type4 system context, " +
520
+ "returning the ObjectID of the currently verified Guard object itself.\n" +
521
+ "This is a rare scenario, typically used for:\n" +
522
+ " 1) Guard referencing its own address as a replacement for a table constant (avoiding hardcoding)\n" +
523
+ " 2) Identifying the current Guard in a rely combination (rare)\n" +
524
+ "Need to confirm whether the use of context(Guard) is necessary and whether the comparison object is correct.",
525
+ affected_stakeholders: ["provider"],
526
+ scenario: "Self-reference misuse: context(Guard) comparing wrong object causes logic invalidation",
527
+ mitigation: "1) Confirm the context(Guard) comparison object is the Guard ObjectID rather than an address constant;" +
528
+ "2) Evaluate whether self-reference is truly needed; usually a table constant can replace it;" +
529
+ "3) Verify in gen_passport tests that self-reference behavior meets expectations",
530
+ };
531
+ },
532
+ },
533
+ {
534
+ id: "R-X1-01",
535
+ data_source_class: "cross_type",
536
+ trigger: "Time-lock query returns 0 causing logic_as_u256_greater_or_equal comparison to always be true",
537
+ check: (ctx) => {
538
+ const str = rootStr(ctx);
539
+ const hasGreaterOrEqual = str.includes("logic_as_u256_greater_or_equal");
540
+ const hasClock = str.includes('"clock"');
541
+ const hasCalcAdd = str.includes("calc_number_add");
542
+ const hasQuery = str.includes('"query"');
543
+ if (!(hasGreaterOrEqual && hasClock && hasCalcAdd && hasQuery))
544
+ return null;
545
+ return {
546
+ id: "R-X1-01",
547
+ data_source_class: "cross_type",
548
+ level: "medium",
549
+ category: "logic_gap",
550
+ title: "Time-lock query may return 0 causing >= comparison to always be true",
551
+ description: "Guard uses logic_as_u256_greater_or_equal for time-lock comparison, and the compared baseline value comes from a query (Type1/2/3 data sources)." +
552
+ "If the query returns 0 (e.g. querying a timestamp of an operation that hasn't happened, or unset node entry time), " +
553
+ "then Clock >= 0 + timeout is always true, the time-lock is effectively void, and the disadvantaged party can bypass the time constraint immediately.",
554
+ affected_stakeholders: ["customer", "provider"],
555
+ scenario: "Time-lock invalidation: query returns 0, making the >= condition always pass",
556
+ mitigation: "1) Use a query that returns the current node entry time (e.g. progress.current_time, id=1272) " +
557
+ "instead of the operation timestamp (e.g. progress.session.forward.time, id=1271);" +
558
+ "2) Add a precondition check query > 0 before the time-lock;" +
559
+ "3) Confirm the query must have a value when the Guard executes (query current node attributes rather than historical operations)",
560
+ };
561
+ },
562
+ },
563
+ {
564
+ id: "R-X1-02",
565
+ data_source_class: "cross_type",
566
+ trigger: "Guard uses logic_as_u256_greater but does not handle null values",
567
+ check: (ctx) => {
568
+ const str = rootStr(ctx);
569
+ if (!(str.includes("logic_as_u256_greater") && str.includes('"query"')))
570
+ return null;
571
+ return {
572
+ id: "R-X1-02",
573
+ data_source_class: "cross_type",
574
+ level: "medium",
575
+ category: "logic_gap",
576
+ title: "Numeric comparison does not handle the case of query returning null",
577
+ description: "Guard uses logic_as_u256_greater for numeric comparison, and operands come from a query (Type1/2/3 data sources)." +
578
+ "If the query returns null (e.g. object does not exist, field not set), the comparison result may be undefined." +
579
+ "In the WoWok protocol null is usually treated as 0, which may cause unexpected pass.",
580
+ affected_stakeholders: ["customer", "provider"],
581
+ scenario: "Null misjudgment: query returns 0, causing > 0 condition to unexpectedly pass or fail",
582
+ mitigation: "1) Add a query result existence check before comparison;" +
583
+ "2) Use query_reward_record_exists or query_progress_history_find to verify first;" +
584
+ "3) Consider adding a logic_and(object exists, numeric comparison) combination",
585
+ };
586
+ },
587
+ },
588
+ {
589
+ id: "R-X1-03",
590
+ data_source_class: "cross_type",
591
+ trigger: "Guard uses logic_string_contains and may be bypassed by substring matching",
592
+ check: (ctx) => {
593
+ const str = rootStr(ctx);
594
+ if (!(str.includes("logic_string_contains") && !str.includes("logic_string_nocase")))
595
+ return null;
596
+ return {
597
+ id: "R-X1-03",
598
+ data_source_class: "cross_type",
599
+ level: "low",
600
+ category: "logic_gap",
601
+ title: "logic_string_contains substring match may be bypassed",
602
+ description: "Guard uses logic_string_contains for string matching." +
603
+ "Substring matching may be bypassed: e.g. when checking 'Completed', 'NotCompleted' also contains 'Completed'." +
604
+ "In addition, case sensitivity may cause unexpected failures. String data may come from Type1 (query object fields), " +
605
+ "Type3 (submitted values), or the context of a rely-dependent Guard.",
606
+ affected_stakeholders: ["customer", "provider"],
607
+ scenario: "Substring mismatch: 'NotCompleted' contains 'Completed', causing false pass",
608
+ mitigation: "1) Prefer logic_equal for exact matching;" +
609
+ "2) If substring matching is needed, add boundary conditions (e.g. prefix + suffix);" +
610
+ "3) Confirm whether case-insensitivity is needed (use the nocase variant)",
611
+ };
612
+ },
613
+ },
614
+ {
615
+ id: "R-X1-04",
616
+ data_source_class: "cross_type",
617
+ trigger: "Guard root is an identifier directly returning Bool",
618
+ check: (ctx) => {
619
+ if (ctx.root?.type !== "identifier")
620
+ return null;
621
+ const entry = ctx.table.find((e) => e.identifier === ctx.root.identifier);
622
+ const isSubmission = entry?.b_submission ?? false;
623
+ return {
624
+ id: "R-X1-04",
625
+ data_source_class: "cross_type",
626
+ level: isSubmission ? "medium" : "low",
627
+ category: "logic_gap",
628
+ title: "Root directly returns identifier value, no operation logic",
629
+ description: "Guard root is an identifier node, directly returning the value (Bool) from table." +
630
+ (isSubmission
631
+ ? "This entry has b_submission=true (Type3 submitted value); the caller can directly submit true to bypass all verification."
632
+ : "This entry has b_submission=false (Type1 constant); the value is fixed but the Guard has no actual verification logic."),
633
+ affected_stakeholders: ["customer", "provider"],
634
+ scenario: isSubmission
635
+ ? "Bypass verification: caller submits true to pass the Guard directly"
636
+ : "No verification logic: Guard always returns a fixed value, providing no actual protection",
637
+ mitigation: isSubmission
638
+ ? "1) Ensure the entry referenced by identifier has b_submission=false (constant);" +
639
+ "2) Or add an additional logic_and condition for cross-validation"
640
+ : "1) Add actual verification logic (query + logic comparison);" +
641
+ "2) Evaluate whether this Guard needs to exist",
642
+ };
643
+ },
644
+ },
645
+ {
646
+ id: "R-X1-05",
647
+ data_source_class: "cross_type",
648
+ trigger: "Allocation Guard may cause some participants to be skipped",
649
+ check: (ctx) => {
650
+ if (ctx.scene?.binding_field !== "order_allocators")
651
+ return null;
652
+ return {
653
+ id: "R-X1-05",
654
+ data_source_class: "cross_type",
655
+ level: "medium",
656
+ category: "game_theory",
657
+ title: "order_allocators first-match-wins may cause unfair allocation",
658
+ description: "order_allocators uses a first-match-wins strategy: the first Allocator whose Guard passes executes the allocation." +
659
+ "If the order is poorly designed, some participants may never get allocated." +
660
+ "For example: if the first Allocator's Guard condition is too broad, subsequent more precise Allocators will never execute." +
661
+ "Allocation Guards typically combine Type1 (query order fields), Type3 (submit Order address), and Type4 (Signer) data.",
662
+ affected_stakeholders: ["provider"],
663
+ scenario: "Allocation skip: the Provider's allocation Allocator is skipped by preceding broad conditions",
664
+ mitigation: "1) Ensure the order_allocators order goes from strict to loose;" +
665
+ "2) Each Allocator's Guard conditions should be mutually exclusive;" +
666
+ "3) Consider using logic_or dependencies rather than sequential ordering",
667
+ };
668
+ },
669
+ },
670
+ {
671
+ id: "R-X1-06",
672
+ data_source_class: "cross_type",
673
+ trigger: "Workflow Guard time-lock may lock the disadvantaged party",
674
+ check: (ctx) => {
675
+ const str = rootStr(ctx);
676
+ if (!(str.includes("clock") && str.includes("calc_number_add")))
677
+ return null;
678
+ return {
679
+ id: "R-X1-06",
680
+ data_source_class: "cross_type",
681
+ level: "medium",
682
+ category: "game_theory",
683
+ title: "Time-lock may lock the disadvantaged party",
684
+ description: "Guard uses a time-lock (context(Clock) + calc_number_add). The time-lock itself is neutral, " +
685
+ "but the locking direction needs to be checked: if the Customer is locked to pay first but cannot accept in time, the Provider gains advantage; " +
686
+ "if the Provider is locked to deliver first but cannot receive payment in time, the Customer gains advantage." +
687
+ "The time-lock combines Type4 (Clock) and Type1/2 (query time fields) data sources.",
688
+ affected_stakeholders: ["customer", "provider"],
689
+ scenario: "Time asymmetry: one party is locked by time while the other has freedom of action",
690
+ mitigation: "1) Ensure the time-lock is symmetric (both parties have time constraints);" +
691
+ "2) Provide an exit mechanism after the time-lock expires (e.g. auto-refund/auto-complete);" +
692
+ "3) Design corresponding timeout Forward nodes in the Machine",
693
+ };
694
+ },
695
+ },
696
+ {
697
+ id: "R-X1-07",
698
+ data_source_class: "cross_type",
699
+ trigger: "Arbitration usage_guard may block legitimate disputes",
700
+ check: (ctx) => {
701
+ if (ctx.scene?.binding_field !== "usage_guard")
702
+ return null;
703
+ const str = rootStr(ctx);
704
+ const andCount = (str.match(/"logic_and"/g) || []).length;
705
+ if (andCount < 3)
706
+ return null;
707
+ return {
708
+ id: "R-X1-07",
709
+ data_source_class: "cross_type",
710
+ level: "high",
711
+ category: "game_theory",
712
+ title: "usage_guard has too many conditions and may block legitimate disputes",
713
+ description: `Detected ${andCount} logic_and combinations. Too many AND conditions make the dispute threshold too high, ` +
714
+ "the Customer may not be able to initiate a legitimate dispute, and the Provider gains an unfair advantage." +
715
+ "usage_guard typically combines Type4 (Signer identity), Type3 (submit Passport credentials), " +
716
+ "and Type1 (query EntityRegistrar verification) data sources.",
717
+ affected_stakeholders: ["customer"],
718
+ scenario: "Dispute threshold too high: Customer cannot initiate a legitimate dispute",
719
+ mitigation: "1) Re-evaluate the necessity of each AND condition;" +
720
+ "2) Consider using logic_or to lower the threshold;" +
721
+ "3) Move non-essential conditions to voting_guard rather than usage_guard",
722
+ };
723
+ },
724
+ },
725
+ {
726
+ id: "R-X1-08",
727
+ data_source_class: "cross_type",
728
+ trigger: "Guard is bound to a published Machine/Service (immutable)",
729
+ check: (ctx) => {
730
+ if (!ctx.scene || ctx.scene.mutable_after_publish)
731
+ return null;
732
+ return {
733
+ id: "R-X1-08",
734
+ data_source_class: "cross_type",
735
+ level: "info",
736
+ category: "binding_risk",
737
+ title: `Guard is bound to immutable ${ctx.scene.host_object} (cannot be modified after publish)`,
738
+ description: `After ${ctx.scene.host_object} is published, ${ctx.scene.binding_field} cannot be modified.` +
739
+ "If the Guard design is flawed, a new Machine/Service must be created and all references migrated." +
740
+ "This is a design constraint rather than a risk, but the Guard design must be correct before publishing.",
741
+ affected_stakeholders: ["provider"],
742
+ scenario: "Irreversible binding: after publish, a flawed Guard design cannot be modified",
743
+ mitigation: "1) Use gen_passport for thorough testing before publishing;" +
744
+ "2) Test both expected-pass and expected-fail scenarios;" +
745
+ "3) Export a Guard backup (guard2file) before publishing",
746
+ };
747
+ },
748
+ },
749
+ {
750
+ id: "R-X1-09",
751
+ data_source_class: "cross_type",
752
+ trigger: "Guard uses rely but the dependent Guard may fail",
753
+ check: (ctx) => {
754
+ if (!ctx.rely || ctx.rely.guards.length === 0)
755
+ return null;
756
+ const logic = ctx.rely.logic_or ? "OR" : "AND";
757
+ return {
758
+ id: "R-X1-09",
759
+ data_source_class: "cross_type",
760
+ level: ctx.rely.logic_or ? "low" : "medium",
761
+ category: "dependency_risk",
762
+ title: `rely ${logic} depends on ${ctx.rely.guards.length} external Guards`,
763
+ description: `Guard uses rely ${logic} to depend on ${ctx.rely.guards.length} external Guards.` +
764
+ (ctx.rely.logic_or
765
+ ? "OR logic: any one passing is enough. If a dependent Guard is loosely designed, it may become a bypass entry point."
766
+ : "AND logic: all dependencies must pass. If a dependent Guard fails or is deleted, the current Guard will always fail.") +
767
+ " rely-dependent Guards must have rep=true (repository.data queries do not depend on runtime submission).",
768
+ affected_stakeholders: ["customer", "provider"],
769
+ scenario: ctx.rely.logic_or
770
+ ? "Dependency bypass: a loose dependent Guard becomes an attack entry point"
771
+ : "Dependency failure: a dependent Guard is deleted, causing the current Guard to always fail",
772
+ mitigation: ctx.rely.logic_or
773
+ ? "1) Review the strictness of each dependent Guard; 2) Ensure all dependent Guards are at least as strict as the current Guard"
774
+ : "1) Confirm all dependent Guards have rep=true and cannot be deleted; 2) Consider whether AND dependency is truly needed",
775
+ };
776
+ },
777
+ },
778
+ {
779
+ id: "R-X1-10",
780
+ data_source_class: "cross_type",
781
+ trigger: "Guard uses repository.data query (query 1167) and the Repository has quote_guard set",
782
+ check: (ctx) => {
783
+ const str = rootStr(ctx);
784
+ if (!(str.includes("repository") && str.includes('"query"')))
785
+ return null;
786
+ return {
787
+ id: "R-X1-10",
788
+ data_source_class: "cross_type",
789
+ level: "medium",
790
+ category: "impack_risk",
791
+ title: "repository.data query's quote_guard is invalid in the verify phase (impack_list is empty)",
792
+ description: "Guard queries repository.data (query 1167). According to passport.move#L289 and passport.rs implementation, " +
793
+ "the impack_list is always empty in the verify phase (only filled after result_for_permission).\n" +
794
+ "Therefore in check_repository_quote_guard (inside query 1167), " +
795
+ "if the Repository policy's quote_guard is Some(addr), " +
796
+ "since addr is not in the empty list, it will always report IMPACK_GUARD_NOT_FOUND.\n" +
797
+ "Only when quote_guard==None can query 1167 pass.\n" +
798
+ "This means: querying Repository data with a quote_guard in the Guard will always fail.",
799
+ affected_stakeholders: ["customer", "provider"],
800
+ scenario: "quote_guard invalidation: impack_list is empty in the verify phase, causing the 1167 query to always fail",
801
+ mitigation: "1) Confirm the queried Repository's quote_guard is None;" +
802
+ "2) If quote authentication is needed, modify the verify loop in the Move layer to maintain impack_list;" +
803
+ "3) Document this limitation clearly: Repositories with quote_guard cannot be queried in the Guard;" +
804
+ "4) Consider using other data sources instead of Repository.data query",
805
+ };
806
+ },
807
+ },
808
+ {
809
+ id: "R-X1-11",
810
+ data_source_class: "cross_type",
811
+ trigger: "Guard uses rely to depend on other Guards; need to confirm the rep flag of dependent Guards is correct",
812
+ check: (ctx) => {
813
+ if (!ctx.rely || ctx.rely.guards.length === 0)
814
+ return null;
815
+ const str = rootStr(ctx);
816
+ const queriesRepoData = str.includes("repository") && str.includes('"query"');
817
+ const hasRepoSubmission = ctx.table.some((e) => e.b_submission && e.value_type === "Address" && e.object_type === "Repository");
818
+ return {
819
+ id: "R-X1-11",
820
+ data_source_class: "cross_type",
821
+ level: queriesRepoData && hasRepoSubmission ? "medium" : "low",
822
+ category: "rep_risk",
823
+ title: "rep semantics needs confirmation (when repository.data query depends on submission, rep=false and cannot be depended on)",
824
+ description: "Guard uses rely to depend on external Guards. In the WoWok protocol, rely-dependent Guards must have rep=true.\n" +
825
+ "Precise rep semantics (guard.rs#L483-L492): repository.data query (query 1167) does not depend on runtime submission.\n" +
826
+ " - rep=true: repository.data query is fully constant-driven (object address b_submission=false and query parameters are not submission)\n" +
827
+ " - rep=false: repository address comes from runtime submission, or query parameters come from submission\n" +
828
+ "Guards with rep=false cannot appear in other Guards' rely lists.\n" +
829
+ (queriesRepoData && hasRepoSubmission
830
+ ? "\nWarning: the current Guard itself queries repository.data and the Repository address comes from submission, " +
831
+ "so its own rep=false and cannot be depended on by other Guards."
832
+ : ""),
833
+ affected_stakeholders: ["provider"],
834
+ scenario: "rep misjudgment: depending on a rep=false Guard causes creation failure, or its own rep=false is wrongly depended on",
835
+ mitigation: "1) Confirm all rely-dependent Guards have rep=true (do not depend on submission to query repository.data);" +
836
+ "2) If the current Guard queries repository.data and the address comes from submission, its own rep=false; annotate that it cannot be depended on;" +
837
+ "3) rep is not 'no Repository dependency', but 'repository.data query does not depend on submission';" +
838
+ "4) Use wowok_buildin_info to query the full definition of the rep flag",
839
+ evidence: queriesRepoData && hasRepoSubmission
840
+ ? "Self rep=false (repository.data query depends on submission)"
841
+ : "Self rep status to be confirmed",
842
+ };
843
+ },
844
+ },
845
+ {
846
+ id: "R-X1-12",
847
+ data_source_class: "cross_type",
848
+ trigger: "Guard table contains b_submission=true entries with vague name descriptions or missing binding_constraint",
849
+ check: (ctx) => {
850
+ const submissionEntries = ctx.table.filter((e) => e.b_submission);
851
+ if (submissionEntries.length === 0)
852
+ return null;
853
+ const vagueEntries = submissionEntries.filter((e) => {
854
+ const name = e.name ?? "";
855
+ return name.length < 10 || /^[a-z_]+$/i.test(name) || name === "";
856
+ });
857
+ if (vagueEntries.length === 0)
858
+ return null;
859
+ return {
860
+ id: "R-X1-12",
861
+ data_source_class: "cross_type",
862
+ level: "medium",
863
+ category: "submission_forgery",
864
+ title: "Submitted data entry description is vague (retained_submission risk: caller may submit wrong data)",
865
+ description: `Guard table has ${vagueEntries.length} b_submission=true entries with vague name descriptions.\n` +
866
+ "The name of a submission entry is the only data contract between the Guard and the caller.\n" +
867
+ "If the name description is unclear (e.g. only 'addr' / 'order_id'), the caller may:\n" +
868
+ " - Submit a wrong-typed object address (e.g. submit a Service address instead of an Order address)\n" +
869
+ " - Submit a wrong value (e.g. inconsistent amount units)\n" +
870
+ " - Confuse submission slots of different Guards in multi-Guard scenarios\n" +
871
+ "Vague submission entries are 'retained' in the table but provide no effective data constraints, " +
872
+ "equivalent to the Guard accepting arbitrary data without validating its semantic correctness.",
873
+ affected_stakeholders: ["customer", "provider"],
874
+ scenario: "Caller submits wrong data due to vague name description; the Guard passes verification but the business logic is wrong",
875
+ mitigation: "1) Each submission entry's name should be a complete natural-language description (e.g. 'The order ID that identifies the target Order for verification');\n" +
876
+ "2) Avoid Technical identifiers as name (e.g. 'order_id' should become 'Order ID, used to query progress status');\n" +
877
+ "3) Add failure_conditions in binding_hint to clarify failure scenarios;\n" +
878
+ "4) Consider adding type validation logic in root (e.g. query the submitted object's objectType and match with expectation)",
879
+ evidence: `Vague entries: ${vagueEntries.map((e) => `identifier=${e.identifier}, name="${e.name}"`).join("; ")}`,
880
+ };
881
+ },
882
+ },
883
+ {
884
+ id: "R-X1-13",
885
+ data_source_class: "cross_type",
886
+ trigger: "Guard references its host object (Host Object) itself — circular reference pattern",
887
+ check: (ctx) => {
888
+ if (!ctx.scene)
889
+ return null;
890
+ const hostType = ctx.scene.host_object;
891
+ const circularEntry = ctx.table.find((e) => !e.b_submission && e.value_type === "Address" &&
892
+ e.object_type === hostType);
893
+ if (!circularEntry)
894
+ return null;
895
+ return {
896
+ id: "R-X1-13",
897
+ data_source_class: "cross_type",
898
+ level: "medium",
899
+ category: "binding_risk",
900
+ title: "Circular reference pattern (Guard references the host object itself; note creation order)",
901
+ description: `In the Guard's table, identifier=${circularEntry.identifier} has object_type equal to the host object type "${hostType}".\n` +
902
+ "Circular reference pattern: the Guard is bound to a Host Object (e.g. Service.buy_guard) and also queries the Host Object's own fields.\n" +
903
+ "Creation order constraints:\n" +
904
+ " 1. The Host Object must be created first (unpublished state)\n" +
905
+ " 2. When the Guard is created, the table uses the Host Object's name (not address); the SDK resolves it at binding time\n" +
906
+ " 3. After the Guard is bound to the Host Object, the Host Object is published\n" +
907
+ "Risks:\n" +
908
+ " - If the Host Object is already published (immutable), the Guard can no longer be bound\n" +
909
+ " - If the Host Object's name is modified after the Guard is created, the Guard's table reference is invalidated\n" +
910
+ " - Circular reference makes the Guard not independently testable (the Host Object must exist to verify)",
911
+ affected_stakeholders: ["provider"],
912
+ scenario: "Guard queries fields of the Service/Machine/Reward it is bound to; wrong creation order causes binding failure",
913
+ mitigation: "1) Ensure the Host Object is unpublished (bPublished=false) when creating and binding the Guard;\n" +
914
+ "2) Use the Host Object's name rather than address in table (the SDK auto-resolves);\n" +
915
+ "3) Perform Guard verification tests after the Host Object is published;\n" +
916
+ "4) Use guard2file to export a Guard backup for restoring references during rebuild",
917
+ evidence: `Circular reference: identifier=${circularEntry.identifier}, object_type="${hostType}" → ${ctx.scene.host_object}`,
918
+ };
919
+ },
920
+ },
921
+ ];
922
+ export function assessGuardRisks(params) {
923
+ const ctx = {
924
+ table: params.table,
925
+ root: params.root,
926
+ rely: params.rely,
927
+ scene: params.scene,
928
+ operation_type: params.operation_type,
929
+ };
930
+ const risks = [];
931
+ for (const rule of RISK_RULES) {
932
+ try {
933
+ const risk = rule.check(ctx);
934
+ if (risk)
935
+ risks.push(risk);
936
+ }
937
+ catch {
938
+ }
939
+ }
940
+ const overall_risk = getOverallRiskLevel(risks);
941
+ const risks_by_data_source = {};
942
+ for (const risk of risks) {
943
+ risks_by_data_source[risk.data_source_class] =
944
+ (risks_by_data_source[risk.data_source_class] ?? 0) + 1;
945
+ }
946
+ const stakeholder_advice = generateStakeholderAdvice(risks, params.scene);
947
+ const needs_human_review = risks.some((r) => r.level === "critical") ||
948
+ risks.filter((r) => r.level === "high").length >= 2;
949
+ const guard_summary = generateGuardSummary(params);
950
+ return {
951
+ guard_summary,
952
+ scene: params.scene,
953
+ risks,
954
+ overall_risk,
955
+ risks_by_data_source,
956
+ stakeholder_advice,
957
+ needs_human_review,
958
+ };
959
+ }
960
+ function getOverallRiskLevel(risks) {
961
+ if (risks.some((r) => r.level === "critical"))
962
+ return "critical";
963
+ if (risks.some((r) => r.level === "high"))
964
+ return "high";
965
+ if (risks.some((r) => r.level === "medium"))
966
+ return "medium";
967
+ if (risks.some((r) => r.level === "low"))
968
+ return "low";
969
+ return "info";
970
+ }
971
+ function generateStakeholderAdvice(risks, scene) {
972
+ const advice = {};
973
+ for (const risk of risks) {
974
+ for (const stakeholder of risk.affected_stakeholders) {
975
+ if (!advice[stakeholder])
976
+ advice[stakeholder] = [];
977
+ advice[stakeholder].push(`[${risk.level.toUpperCase()}] ${risk.title}: ${risk.mitigation}`);
978
+ }
979
+ }
980
+ if (scene) {
981
+ switch (scene.binding_field) {
982
+ case "buy_guard":
983
+ if (!advice.customer)
984
+ advice.customer = [];
985
+ advice.customer.push("Before purchase, verify the buy_guard logic to ensure your identity/credentials can pass validation");
986
+ break;
987
+ case "order_allocators":
988
+ if (!advice.provider)
989
+ advice.provider = [];
990
+ advice.provider.push("Verify the order_allocators ordering to ensure your Allocator will not be skipped by preceding conditions");
991
+ break;
992
+ case "voting_guard":
993
+ if (!advice.arbitrator)
994
+ advice.arbitrator = [];
995
+ advice.arbitrator.push("Confirm the voting weight source is trustworthy; prefer querying EntityRegistrar rather than user-submitted data");
996
+ break;
997
+ case "Forward.guard":
998
+ if (!advice.customer)
999
+ advice.customer = [];
1000
+ advice.customer.push("Verify the Forward.guard conditions to ensure you can satisfy the advancement criteria and avoid locked funds");
1001
+ break;
1002
+ }
1003
+ }
1004
+ return advice;
1005
+ }
1006
+ function generateGuardSummary(params) {
1007
+ const parts = [];
1008
+ parts.push(`table entries: ${params.table.length}`);
1009
+ const submissions = params.table.filter((e) => e.b_submission).length;
1010
+ parts.push(`submitted data: ${submissions} entries`);
1011
+ parts.push(`root type: ${params.root?.type ?? "unknown"}`);
1012
+ if (params.rely) {
1013
+ parts.push(`rely: ${params.rely.guards.length} dependencies (${params.rely.logic_or ? "OR" : "AND"})`);
1014
+ }
1015
+ return parts.join(", ");
1016
+ }
1017
+ export function assessGuardRisksForOperation(operation_type, data) {
1018
+ if (operation_type !== "guard")
1019
+ return null;
1020
+ const table = data?.table ?? [];
1021
+ const root = data?.root;
1022
+ const rely = data?.rely;
1023
+ let scene;
1024
+ return assessGuardRisks({ table, root, rely, scene, operation_type });
1025
+ }
1026
+ export function getRiskSummary(assessment) {
1027
+ return {
1028
+ risk_count: assessment.risks.length,
1029
+ critical_count: assessment.risks.filter((r) => r.level === "critical").length,
1030
+ high_count: assessment.risks.filter((r) => r.level === "high").length,
1031
+ needs_human_review: assessment.needs_human_review,
1032
+ top_risks: assessment.risks
1033
+ .filter((r) => r.level === "critical" || r.level === "high")
1034
+ .slice(0, 3)
1035
+ .map((r) => r.title),
1036
+ };
1037
+ }
1038
+ export function getRiskRulesByDataSourceClass(dataSourceClass) {
1039
+ return RISK_RULES.filter((r) => r.data_source_class === dataSourceClass);
1040
+ }
1041
+ export function getAllRiskRules() {
1042
+ return RISK_RULES;
1043
+ }
1044
+ export function getRiskRulesCount() {
1045
+ return RISK_RULES.length;
1046
+ }