@wowok/agent-mcp 2.5.3 → 2.5.5

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 (69) hide show
  1. package/README.md +33 -26
  2. package/dist/customer/index.d.ts +2 -2
  3. package/dist/customer/index.js +1 -1
  4. package/dist/customer/info-puzzle.d.ts +39 -2
  5. package/dist/customer/info-puzzle.js +370 -29
  6. package/dist/customer/risk-assessment.js +51 -14
  7. package/dist/customer/types.d.ts +85 -0
  8. package/dist/knowledge/machine-ledger.js +32 -29
  9. package/dist/knowledge/machine-risk.js +23 -0
  10. package/dist/knowledge/machine-templates.js +118 -86
  11. package/dist/knowledge/reward-confirm.d.ts +3 -0
  12. package/dist/knowledge/reward-confirm.js +30 -0
  13. package/dist/knowledge/reward-puzzle.d.ts +1 -0
  14. package/dist/knowledge/reward-puzzle.js +12 -0
  15. package/dist/knowledge/reward-risk.d.ts +4 -1
  16. package/dist/knowledge/reward-risk.js +85 -3
  17. package/dist/knowledge/reward-templates.d.ts +1 -1
  18. package/dist/knowledge/reward-templates.js +77 -5
  19. package/dist/knowledge/tools-reference.js +5 -4
  20. package/dist/knowledge/trust-metrics.d.ts +4 -0
  21. package/dist/knowledge/trust-metrics.js +67 -7
  22. package/dist/project/evaluation.d.ts +53 -0
  23. package/dist/project/evaluation.js +853 -0
  24. package/dist/project/graph-builder.d.ts +43 -0
  25. package/dist/project/graph-builder.js +572 -0
  26. package/dist/project/handlers.d.ts +152 -0
  27. package/dist/project/handlers.js +458 -0
  28. package/dist/project/index.d.ts +1 -0
  29. package/dist/project/index.js +24 -1
  30. package/dist/project/query.d.ts +1 -0
  31. package/dist/project/query.js +2 -0
  32. package/dist/project/semantic-assembler.d.ts +93 -0
  33. package/dist/project/semantic-assembler.js +345 -0
  34. package/dist/schema/call/arbitration.d.ts +54 -54
  35. package/dist/schema/call/base.js +1 -1
  36. package/dist/schema/call/demand.d.ts +48 -48
  37. package/dist/schema/operations.d.ts +76 -76
  38. package/dist/schema/project/index.d.ts +1558 -3885
  39. package/dist/schema/project/index.js +357 -961
  40. package/dist/schema/trust/index.d.ts +24 -24
  41. package/dist/schemas/bridge_operation.schema.json +1 -1
  42. package/dist/schemas/guard2file.schema.json +1 -1
  43. package/dist/schemas/index.json +2 -2
  44. package/dist/schemas/machineNode2file.schema.json +1 -1
  45. package/dist/schemas/onchain_operations.schema.json +5 -5
  46. package/dist/schemas/onchain_operations_allocation.schema.json +1 -1
  47. package/dist/schemas/onchain_operations_arbitration.schema.json +1 -1
  48. package/dist/schemas/onchain_operations_contact.schema.json +1 -1
  49. package/dist/schemas/onchain_operations_demand.schema.json +1 -1
  50. package/dist/schemas/onchain_operations_gen_passport.schema.json +2 -2
  51. package/dist/schemas/onchain_operations_gen_proof.schema.json +2 -2
  52. package/dist/schemas/onchain_operations_guard.schema.json +1 -1
  53. package/dist/schemas/onchain_operations_machine.schema.json +1 -1
  54. package/dist/schemas/onchain_operations_order.schema.json +1 -1
  55. package/dist/schemas/onchain_operations_payment.schema.json +1 -1
  56. package/dist/schemas/onchain_operations_permission.schema.json +1 -1
  57. package/dist/schemas/onchain_operations_personal.schema.json +1 -1
  58. package/dist/schemas/onchain_operations_progress.schema.json +1 -1
  59. package/dist/schemas/onchain_operations_proof.schema.json +1 -1
  60. package/dist/schemas/onchain_operations_repository.schema.json +1 -1
  61. package/dist/schemas/onchain_operations_reward.schema.json +1 -1
  62. package/dist/schemas/onchain_operations_service.schema.json +1 -1
  63. package/dist/schemas/onchain_operations_treasury.schema.json +1 -1
  64. package/dist/schemas/project_operation.output.json +975 -2471
  65. package/dist/schemas/project_operation.schema.json +207 -534
  66. package/dist/tools/handlers/onchain.js +97 -19
  67. package/dist/tools/handlers/project.js +34 -1046
  68. package/dist/tools/index.js +84 -55
  69. package/package.json +2 -2
@@ -81,6 +81,7 @@ export interface RewardJsonForConfirm {
81
81
  guard_expiration_time?: number | null;
82
82
  owner_receive?: unknown;
83
83
  um?: string | null;
84
+ guard_expected_progress_state?: string;
84
85
  }
85
86
  export interface RewardConfirmGateInput {
86
87
  reward_json: RewardJsonForConfirm;
@@ -97,6 +98,8 @@ export interface RewardConfirmGateInput {
97
98
  passport_submission_value_types?: Record<number, string>;
98
99
  passport_identifier_is_address?: Record<number, boolean>;
99
100
  guard_store_from_id_compatible?: Record<string, boolean>;
101
+ user_intent_phrases?: string[];
102
+ machine_has_wonder_node?: boolean;
100
103
  skip_user_confirmation?: boolean;
101
104
  skip_environment_check?: boolean;
102
105
  }
@@ -11,6 +11,7 @@ export const REWARD_OPERATION_CHECKLIST = [
11
11
  { id: "C-R-08", description: "claim: Passport is provided (SDK W_ERROR if missing)", passed: false, message: "" },
12
12
  { id: "C-R-09", description: "owner_receive (156): user double-confirms blast radius", passed: false, message: "" },
13
13
  { id: "C-R-10", description: "guard_expiration_time_add (155): new time > current clock", passed: false, message: "" },
14
+ { id: "C-R-11", description: "guard_add: Guard's progress.current expected value matches business intent (praise→wonder, completion→completed)", passed: false, message: "" },
14
15
  ];
15
16
  function runStaticChecklist(input) {
16
17
  const items = REWARD_OPERATION_CHECKLIST.map(c => ({ ...c }));
@@ -133,6 +134,22 @@ function runStaticChecklist(input) {
133
134
  else {
134
135
  cr10.passed = true;
135
136
  }
137
+ const cr11 = items.find(i => i.id === "C-R-11");
138
+ if (data.guard_expected_progress_state && input.user_intent_phrases && input.user_intent_phrases.length > 0) {
139
+ const intentLower = input.user_intent_phrases.join(" ").toLowerCase();
140
+ const praiseKeywords = ["好评", "praise", "wonder", "thumbs_up", "positive review", "satisfaction reward", "好评奖励"];
141
+ const isPraiseIntent = praiseKeywords.some(kw => intentLower.includes(kw.toLowerCase()));
142
+ if (isPraiseIntent && input.machine_has_wonder_node !== false && data.guard_expected_progress_state !== "wonder") {
143
+ cr11.passed = false;
144
+ cr11.message = `intent=praise but Guard checks "${data.guard_expected_progress_state}" instead of "wonder" — R-R-6-01 violation`;
145
+ }
146
+ else {
147
+ cr11.passed = true;
148
+ }
149
+ }
150
+ else {
151
+ cr11.passed = true;
152
+ }
136
153
  return {
137
154
  all_passed: items.filter(i => i.id !== "C-R-09").every(i => i.passed),
138
155
  items,
@@ -162,6 +179,9 @@ function adaptRiskAssessment(input) {
162
179
  passport_submission_value_types: input.passport_submission_value_types,
163
180
  passport_identifier_is_address: input.passport_identifier_is_address,
164
181
  guard_store_from_id_compatible: input.guard_store_from_id_compatible,
182
+ user_intent_phrases: input.user_intent_phrases,
183
+ guard_expected_progress_state: input.reward_json.guard_expected_progress_state,
184
+ machine_has_wonder_node: input.machine_has_wonder_node,
165
185
  };
166
186
  return assessRewardRisks(ctx);
167
187
  }
@@ -201,6 +221,14 @@ export const REWARD_CONFIRMATION_QUESTIONS = [
201
221
  requires_explicit_yes: false,
202
222
  related_risk_ids: ["R-R-5-02"],
203
223
  },
224
+ {
225
+ id: "QRW7",
226
+ question: "⚠️ For guard_add with progress.current check: does the Guard's expected progress node match the business intent? " +
227
+ "If intent is '好评/praise', Guard must check 'wonder' (NOT 'completed'). " +
228
+ "Premature claim at wrong node drains reward pool — Guard is immutable after creation.",
229
+ requires_explicit_yes: true,
230
+ related_risk_ids: ["R-R-6-01", "R-R-6-02"],
231
+ },
204
232
  ];
205
233
  function processUserConfirmation(input, assessment) {
206
234
  const questions = [...REWARD_CONFIRMATION_QUESTIONS];
@@ -217,6 +245,8 @@ function processUserConfirmation(input, assessment) {
217
245
  continue;
218
246
  if (q.id === "QRW6" && !data.coin_add)
219
247
  continue;
248
+ if (q.id === "QRW7" && (!data.guard_add || !data.guard_expected_progress_state))
249
+ continue;
220
250
  filtered.push(q);
221
251
  }
222
252
  if (input.skip_user_confirmation) {
@@ -48,6 +48,7 @@ export interface RewardConstraintChecklist {
48
48
  F_R_06_recipient_amount_valid_pairing: boolean;
49
49
  F_R_07_coin_type_matches_reward_t: boolean;
50
50
  F_R_08_passport_required_for_claim: boolean;
51
+ F_R_09_progress_node_matches_intent: boolean;
51
52
  }
52
53
  export type RewardPuzzleDimension = "A" | "B" | "C" | "D" | "E" | "F";
53
54
  export interface RewardPuzzle {
@@ -29,6 +29,7 @@ export function initPuzzleFromIntent(intent) {
29
29
  F_R_06_recipient_amount_valid_pairing: false,
30
30
  F_R_07_coin_type_matches_reward_t: false,
31
31
  F_R_08_passport_required_for_claim: false,
32
+ F_R_09_progress_node_matches_intent: true,
32
33
  };
33
34
  return puzzle;
34
35
  }
@@ -177,6 +178,17 @@ export function validateConstraints(puzzle) {
177
178
  message: "claim requires Passport — SDK W_ERROR if missing",
178
179
  });
179
180
  }
181
+ if (puzzle.guard && puzzle.intent && puzzle.constraints) {
182
+ if (!puzzle.constraints.F_R_09_progress_node_matches_intent) {
183
+ violations.push({
184
+ constraint_id: "F-R-09",
185
+ severity: "HIGH",
186
+ message: "Guard's expected progress.current value does not match business intent — " +
187
+ "praise reward (好评/wonder) must check 'wonder' node, not 'completed'. " +
188
+ "Guard is immutable after creation; mismatch requires full rebuild.",
189
+ });
190
+ }
191
+ }
180
192
  return violations;
181
193
  }
182
194
  export function generateConfirmationText(puzzle) {
@@ -1,6 +1,6 @@
1
1
  import { type RewardScene, type RewardAmountType } from "./reward-ledger.js";
2
2
  export type RewardRiskLevel = "CRITICAL" | "HIGH" | "MEDIUM" | "LOW";
3
- export type RewardRiskCategory = "structural" | "semantic" | "permission" | "lifecycle" | "cross_object";
3
+ export type RewardRiskCategory = "structural" | "semantic" | "permission" | "lifecycle" | "cross_object" | "business_semantic";
4
4
  export interface RewardRisk {
5
5
  id: string;
6
6
  level: RewardRiskLevel;
@@ -65,6 +65,9 @@ export interface RewardRiskCheckContext {
65
65
  passport_submission_value_types?: Record<number, string>;
66
66
  passport_identifier_is_address?: Record<number, boolean>;
67
67
  guard_store_from_id_compatible?: Record<string, boolean>;
68
+ user_intent_phrases?: string[];
69
+ guard_expected_progress_state?: string;
70
+ machine_has_wonder_node?: boolean;
68
71
  }
69
72
  export declare const REWARD_RISK_VERSION = "1.0.0";
70
73
  export declare function getAllRewardRiskRules(): RewardRiskRule[];
@@ -469,12 +469,94 @@ const R_R_5_03 = {
469
469
  return null;
470
470
  },
471
471
  };
472
+ const R_R_6_01 = {
473
+ id: "R-R-6-01",
474
+ category: "business_semantic",
475
+ trigger: "intent mentions praise/好评 but Guard checks non-wonder progress node",
476
+ check: (ctx) => {
477
+ if (!ctx.user_intent_phrases || ctx.user_intent_phrases.length === 0)
478
+ return null;
479
+ if (!ctx.guard_expected_progress_state)
480
+ return null;
481
+ const intentLower = ctx.user_intent_phrases.join(" ").toLowerCase();
482
+ const praiseKeywords = [
483
+ "好评", "praise", "wonder", "thumbs_up",
484
+ "positive review", "satisfaction reward", "好评奖励",
485
+ ];
486
+ const isPraiseIntent = praiseKeywords.some(kw => intentLower.includes(kw.toLowerCase()));
487
+ if (!isPraiseIntent)
488
+ return null;
489
+ if (ctx.machine_has_wonder_node === false)
490
+ return null;
491
+ const expected = ctx.guard_expected_progress_state;
492
+ if (expected !== "wonder") {
493
+ return {
494
+ id: "R-R-6-01",
495
+ level: "HIGH",
496
+ category: "business_semantic",
497
+ title: `Guard checks progress=="${expected}" but intent indicates praise reward (wonder node)`,
498
+ description: `User intent mentions praise/好评/wonder, which maps to the 'wonder' progress node ` +
499
+ `(customer gives positive review AFTER service completion). But the Guard's table bakes ` +
500
+ `expected state="${expected}", allowing reward claim at the wrong lifecycle stage. ` +
501
+ `This violates the business semantics: "好评奖励" should only be claimable AFTER the ` +
502
+ `customer advances to the 'wonder' node, not before. ` +
503
+ `Guard is immutable — fixing this requires creating a new Guard + Reward pair.`,
504
+ affected_stakeholders: ["owner", "service_provider", "claimer"],
505
+ scenario: "Designer builds Guard checking 'completed' instead of 'wonder' for a praise reward",
506
+ mitigation: "Set the Guard table's expected progress state to 'wonder' (the positive-review node). " +
507
+ "The correct pattern: ordered → in_service → completed → wonder (praise) triggers reward claim. " +
508
+ "Reference: reward-templates.ts wonder_praise template.",
509
+ evidence: `intent="${intentLower}", expected_state="${expected}", expected_wonder=true`,
510
+ auto_fixable: false,
511
+ };
512
+ }
513
+ return null;
514
+ },
515
+ };
516
+ const R_R_6_02 = {
517
+ id: "R-R-6-02",
518
+ category: "business_semantic",
519
+ trigger: "Guard checks wonder node but intent does not mention praise",
520
+ check: (ctx) => {
521
+ if (!ctx.user_intent_phrases || ctx.user_intent_phrases.length === 0)
522
+ return null;
523
+ if (!ctx.guard_expected_progress_state)
524
+ return null;
525
+ if (ctx.guard_expected_progress_state !== "wonder")
526
+ return null;
527
+ const intentLower = ctx.user_intent_phrases.join(" ").toLowerCase();
528
+ const praiseKeywords = [
529
+ "好评", "praise", "wonder", "thumbs_up",
530
+ "positive review", "satisfaction reward", "好评奖励",
531
+ ];
532
+ const isPraiseIntent = praiseKeywords.some(kw => intentLower.includes(kw.toLowerCase()));
533
+ if (isPraiseIntent)
534
+ return null;
535
+ return {
536
+ id: "R-R-6-02",
537
+ level: "MEDIUM",
538
+ category: "business_semantic",
539
+ title: "Guard checks wonder node but intent does not mention praise",
540
+ description: `Guard's expected progress state is "wonder" (positive-review node), but the user intent ` +
541
+ `does not mention any praise/好评 keyword. This may be a copy-paste from a wonder_praise ` +
542
+ `template without adjusting the Guard for the actual business semantics. If this is a ` +
543
+ `general feedback reward (wonder_feedback), this is fine. Otherwise, verify the node choice.`,
544
+ affected_stakeholders: ["owner"],
545
+ scenario: "Designer copies wonder_praise template but actually wants a completion-based reward",
546
+ mitigation: "Verify: if intent is praise reward, add '好评/praise' to description. " +
547
+ "If intent is completion-based reward, change Guard to check 'completed' node.",
548
+ evidence: `expected_state="wonder", intent="${intentLower}" (no praise keyword)`,
549
+ auto_fixable: false,
550
+ };
551
+ },
552
+ };
472
553
  const ALL_RULES = [
473
554
  R_R_1_01, R_R_1_02, R_R_1_03,
474
555
  R_R_2_01, R_R_2_02, R_R_2_03, R_R_2_04,
475
556
  R_R_3_01, R_R_3_02, R_R_3_03,
476
557
  R_R_4_01, R_R_4_02, R_R_4_03, R_R_4_04,
477
558
  R_R_5_01, R_R_5_02, R_R_5_03,
559
+ R_R_6_01, R_R_6_02,
478
560
  ];
479
561
  export const REWARD_RISK_VERSION = "1.0.0";
480
562
  export function getAllRewardRiskRules() {
@@ -529,13 +611,13 @@ export const REWARD_STAKEHOLDERS = [
529
611
  export function getRewardRiskRulesByStakeholder(stakeholder) {
530
612
  return ALL_RULES.filter(rule => {
531
613
  if (stakeholder === "owner") {
532
- return ["structural", "permission", "lifecycle"].includes(rule.category);
614
+ return ["structural", "permission", "lifecycle", "business_semantic"].includes(rule.category);
533
615
  }
534
616
  if (stakeholder === "claimer") {
535
- return rule.id.startsWith("R-R-4-0") || rule.id === "R-R-5-01" || rule.id === "R-R-1-02";
617
+ return rule.id.startsWith("R-R-4-0") || rule.id === "R-R-5-01" || rule.id === "R-R-1-02" || rule.id === "R-R-6-01";
536
618
  }
537
619
  if (stakeholder === "service_provider") {
538
- return rule.id === "R-R-4-02" || rule.id === "R-R-3-01" || rule.id === "R-R-3-02";
620
+ return rule.id === "R-R-4-02" || rule.id === "R-R-3-01" || rule.id === "R-R-3-02" || rule.id === "R-R-6-01";
539
621
  }
540
622
  if (stakeholder === "system") {
541
623
  return rule.category === "cross_object";
@@ -1,4 +1,4 @@
1
- export type RewardTemplateType = "first_order" | "referral" | "loyalty" | "flash_sale" | "bulk_discount" | "milestone" | "cashback";
1
+ export type RewardTemplateType = "first_order" | "referral" | "loyalty" | "flash_sale" | "bulk_discount" | "milestone" | "cashback" | "wonder_praise" | "wonder_feedback";
2
2
  export interface RewardTemplate {
3
3
  type: RewardTemplateType;
4
4
  name: string;
@@ -92,6 +92,68 @@ export const REWARD_TEMPLATES = [
92
92
  example: "Service reaches the 100-order milestone; the first 50 customers each receive 5 WOW extra reward.",
93
93
  relevantGuardOps: ["query", "repository_read"],
94
94
  },
95
+ {
96
+ type: "wonder_praise",
97
+ name: "Wonder-node praise reward (post-completion positive feedback)",
98
+ description: "Rewards customers who advance their order Progress to the 'wonder' node after normal completion — " +
99
+ "a user-driven positive-feedback mechanism. The machine design pattern is: " +
100
+ "place_order → booked → in_progress → completed → (wonder | no_wonder). " +
101
+ "After the order reaches 'completed' (terminal business state), the OrderHolder " +
102
+ "(namedOperator='') can advance Progress to 'wonder' (positive review) or 'no_wonder' " +
103
+ "(negative review). The Reward's claim_guard verifies Progress.current == 'wonder' " +
104
+ "AND order.service == this Service, so only satisfied customers can claim. " +
105
+ "This creates an on-chain reputation signal that benefits both the merchant " +
106
+ "(public proof of quality) and the customer (monetary reward for honest feedback).",
107
+ guardCondition: "Guard verifies: (1) Progress.current == 'wonder' (customer advanced to praise node), " +
108
+ "(2) Progress.task == order_address AND order.service == this Service, " +
109
+ "(3) Progress.machine == service.machine (snapshot match), " +
110
+ "(4) claimer is the order holder (order.holder == signer). " +
111
+ "Recommended Guard ops: query Progress object, query Order object, " +
112
+ "verify Progress.current field equals 'wonder'.",
113
+ amountRange: { min: "0.1WOW", max: "20WOW" },
114
+ allocationStrategy: "fixed",
115
+ parameters: [
116
+ { name: "amount", type: "string", description: "Reward amount per praise (e.g., '1WOW')", required: true },
117
+ { name: "budget", type: "string", description: "Total budget (e.g., '500WOW')", required: true },
118
+ { name: "expiration_time", type: "number", description: "Claim expiration timestamp (ms); 0 = no expiration", required: false },
119
+ { name: "max_claims_per_user", type: "number", description: "Max claims per user (default 1, prevents duplicate praise rewards)", required: false },
120
+ ],
121
+ example: "A photography service machine: place_order → booked → in_progress → completed → wonder. " +
122
+ "After delivery, the customer advances Progress to 'wonder' if satisfied. " +
123
+ "The Reward's Guard verifies Progress.current == 'wonder', and the customer claims 1 WOW. " +
124
+ "Merchant benefits from on-chain proof of customer satisfaction.",
125
+ relevantGuardOps: ["query", "progress_node_check"],
126
+ },
127
+ {
128
+ type: "wonder_feedback",
129
+ name: "Wonder-node feedback collection (covers wonder & no_wonder)",
130
+ description: "A feedback-collection Reward that pays a small amount for EITHER positive (wonder) OR " +
131
+ "negative (no_wonder) feedback, encouraging customers to leave honest reviews. " +
132
+ "The machine design pattern is the same as wonder_praise: " +
133
+ "place_order → booked → in_progress → completed → (wonder | no_wonder). " +
134
+ "The Reward's claim_guard verifies Progress.current ∈ {'wonder', 'no_wonder'} — both nodes " +
135
+ "trigger the reward. This is useful for merchants who want to gather feedback signal " +
136
+ "regardless of sentiment, e.g., for product improvement or public reputation metrics. " +
137
+ "Pair with a Repository that records the feedback node for historical analysis.",
138
+ guardCondition: "Guard verifies: (1) Progress.current ∈ {'wonder', 'no_wonder'}, " +
139
+ "(2) Progress.task == order_address AND order.service == this Service, " +
140
+ "(3) claimer is the order holder. " +
141
+ "The Guard should query the Progress object and check that current node is one of the " +
142
+ "two feedback nodes. Optional: write the feedback node to a Repository for analytics.",
143
+ amountRange: { min: "0.05WOW", max: "5WOW" },
144
+ allocationStrategy: "fixed",
145
+ parameters: [
146
+ { name: "amount", type: "string", description: "Reward amount per feedback (e.g., '0.5WOW')", required: true },
147
+ { name: "budget", type: "string", description: "Total budget (e.g., '200WOW')", required: true },
148
+ { name: "feedback_nodes", type: "string", description: "Comma-separated list of feedback node names (default: 'wonder,no_wonder')", required: false },
149
+ { name: "expiration_time", type: "number", description: "Claim expiration timestamp (ms); 0 = no expiration", required: false },
150
+ ],
151
+ example: "A freelance design service: place_order → ... → completed → (wonder | no_wonder). " +
152
+ "Customer advances to 'wonder' (liked the work) or 'no_wonder' (didn't like it). " +
153
+ "Both trigger a 0.5 WOW feedback reward. Merchant tracks the wonder/no_wonder ratio " +
154
+ "in a Repository to identify quality issues and improve service.",
155
+ relevantGuardOps: ["query", "progress_node_check", "repository_write"],
156
+ },
95
157
  ];
96
158
  const TEMPLATE_INDEX = new Map(REWARD_TEMPLATES.map((t) => [t.type, t]));
97
159
  export function getRewardTemplate(type) {
@@ -102,22 +164,32 @@ export function listRewardTemplates() {
102
164
  }
103
165
  export function suggestRewardTemplate(intent) {
104
166
  const lower = intent.toLowerCase();
167
+ if (lower.includes("wonder") || lower.includes("praise") || lower.includes("thumbs_up")
168
+ || lower.includes("好评") || lower.includes("positive review")
169
+ || lower.includes("satisfaction reward")) {
170
+ return getRewardTemplate("wonder_praise");
171
+ }
172
+ if (lower.includes("feedback") || lower.includes("review collection")
173
+ || lower.includes("no_wonder") || lower.includes("thumbs_down")
174
+ || lower.includes("差评") || lower.includes("both sentiment")) {
175
+ return getRewardTemplate("wonder_feedback");
176
+ }
105
177
  if (lower.includes("first order") || lower.includes("new") || lower.includes("first")) {
106
178
  return getRewardTemplate("first_order");
107
179
  }
108
- if (lower.includes("referral") || lower.includes("viral") || lower.includes("referral")) {
180
+ if (lower.includes("referral") || lower.includes("viral")) {
109
181
  return getRewardTemplate("referral");
110
182
  }
111
- if (lower.includes("repeat") || lower.includes("loyalty") || lower.includes("loyalty")) {
183
+ if (lower.includes("repeat") || lower.includes("loyalty")) {
112
184
  return getRewardTemplate("loyalty");
113
185
  }
114
- if (lower.includes("limited-time") || lower.includes("flash") || lower.includes("flash")) {
186
+ if (lower.includes("limited-time") || lower.includes("flash")) {
115
187
  return getRewardTemplate("flash_sale");
116
188
  }
117
- if (lower.includes("cashback") || lower.includes("cashback")) {
189
+ if (lower.includes("cashback")) {
118
190
  return getRewardTemplate("cashback");
119
191
  }
120
- if (lower.includes("milestone") || lower.includes("milestone")) {
192
+ if (lower.includes("milestone")) {
121
193
  return getRewardTemplate("milestone");
122
194
  }
123
195
  return undefined;
@@ -105,11 +105,12 @@ export const TOOLS_REFERENCE = [
105
105
  },
106
106
  {
107
107
  name: "project_operation",
108
- summary: "Project namespace + object dependency graph (DAG) + GLM5 C1-C4 composite actions.",
109
- actions: ["list_projects", "list_objects", "shareable", "dependencies", "referenced_by", "pre_publish_check", "cross_project_refs", "graph_stats", "save_graph", "load_graph", "analyze_intent", "aggregate_risks", "generate_deployment_doc", "trace_substeps"],
108
+ summary: "Project entity management (SQLite) + 3-pathway graph construction + dual rule-based/LLM-assisted evaluation engine.",
109
+ actions: ["list_projects", "create_project", "create_project_from_onchain", "update_project", "get_project_detail", "add_object", "remove_object", "create_version", "build_graph", "get_graph", "evaluate_project", "save_evaluation", "compare_projects", "refresh_objects", "get_object_diff", "assemble_context"],
110
110
  notes: [
111
- "GLM5: C1-C4 actions drive the 5-stage project-based deployment flow.",
112
- "Non-blocking: only CRITICAL risks block; HIGH/MEDIUM/LOW are advisory.",
111
+ "GLM6: Projects are first-class entities with SQLite persistence, rigid project-object relationships.",
112
+ "Evaluation: risk/trust/completeness are rule-based (computed locally). value/worth_buying require LLM assistance (returns a prompt).",
113
+ "Graph: 3 pathways — internal references (configurable depth), Registrar inbound (O(1)), potential relationships.",
113
114
  ],
114
115
  },
115
116
  {
@@ -1,6 +1,9 @@
1
1
  export interface ServiceTrustMetrics {
2
2
  arbitrationScore?: number;
3
3
  arbitrationCases?: number;
4
+ arbitrationVotingGuardCount?: number;
5
+ arbitrationFeeBalance?: bigint;
6
+ arbitrationPaused?: boolean;
4
7
  reviewStats?: {
5
8
  likes: number;
6
9
  dislikes: number;
@@ -11,6 +14,7 @@ export interface ServiceTrustMetrics {
11
14
  completedRate?: number;
12
15
  avgCompletionTime?: number;
13
16
  compensationFundBalance?: bigint;
17
+ typicalOrderAmount?: bigint;
14
18
  hasPublishedEvents?: boolean;
15
19
  hasMachineBound?: boolean;
16
20
  hasBuyGuard?: boolean;
@@ -38,16 +38,51 @@ export function computeServiceTrustScore(metrics) {
38
38
  }
39
39
  function computeArbitrationDimension(metrics) {
40
40
  const maxScore = 30;
41
- if (metrics.arbitrationScore === undefined) {
42
- return { name: "arbitration", score: maxScore * 0.5, maxScore, description: "Arbitration trust score (no data, default moderate)", humanReadable: "Arbitration record: no data" };
41
+ if (metrics.arbitrationScore === undefined && metrics.arbitrationVotingGuardCount === undefined) {
42
+ return {
43
+ name: "arbitration",
44
+ score: maxScore * 0.25,
45
+ maxScore,
46
+ description: "Arbitration trust score (no data; default low because arbitration is critical)",
47
+ humanReadable: "Arbitration: no data (default low — critical missing)",
48
+ };
43
49
  }
44
- const score = Math.round((metrics.arbitrationScore / 100) * maxScore);
50
+ let score = 0;
51
+ const parts = [];
52
+ if (metrics.arbitrationScore !== undefined) {
53
+ const baseScore = Math.round((metrics.arbitrationScore / 100) * 10);
54
+ score += baseScore;
55
+ parts.push(`score ${metrics.arbitrationScore}/100`);
56
+ }
57
+ else {
58
+ score += 3;
59
+ }
60
+ if (metrics.arbitrationVotingGuardCount !== undefined && metrics.arbitrationVotingGuardCount > 0) {
61
+ score += 5;
62
+ parts.push(`${metrics.arbitrationVotingGuardCount} voting_guard(s)`);
63
+ }
64
+ if (metrics.arbitrationFeeBalance !== undefined && metrics.arbitrationFeeBalance > 0n) {
65
+ score += 5;
66
+ parts.push("fee funded");
67
+ }
68
+ if (metrics.arbitrationPaused === false) {
69
+ score += 5;
70
+ parts.push("active");
71
+ }
72
+ else if (metrics.arbitrationPaused === true) {
73
+ parts.push("paused");
74
+ }
75
+ if (metrics.arbitrationCases !== undefined && metrics.arbitrationCases > 0) {
76
+ score += 5;
77
+ parts.push(`${metrics.arbitrationCases} case(s)`);
78
+ }
79
+ score = Math.min(maxScore, score);
45
80
  return {
46
81
  name: "arbitration",
47
82
  score,
48
83
  maxScore,
49
- description: `Arbitration trust score ${metrics.arbitrationScore}/100`,
50
- humanReadable: `Arbitration trust: ${metrics.arbitrationScore}/100${metrics.arbitrationCases !== undefined ? ` (${metrics.arbitrationCases} cases)` : ""}`,
84
+ description: `Arbitration config: ${parts.join(", ")}`,
85
+ humanReadable: `Arbitration: ${parts.join(", ")}`,
51
86
  };
52
87
  }
53
88
  function computeReviewDimension(metrics) {
@@ -94,6 +129,31 @@ function computeFundDimension(metrics) {
94
129
  if (metrics.compensationFundBalance === undefined || metrics.compensationFundBalance === 0n) {
95
130
  return { name: "fund_safety", score: 0, maxScore, description: "No compensation fund", humanReadable: "Compensation fund: none" };
96
131
  }
132
+ const fund = metrics.compensationFundBalance;
133
+ if (metrics.typicalOrderAmount !== undefined && metrics.typicalOrderAmount > 0n) {
134
+ const ratio = Number((fund * 100n) / metrics.typicalOrderAmount) / 100;
135
+ let score;
136
+ let humanReadable;
137
+ if (ratio >= 10) {
138
+ score = maxScore;
139
+ humanReadable = `Compensation fund: ${ratio.toFixed(1)}x order amount (excellent)`;
140
+ }
141
+ else if (ratio >= 1) {
142
+ score = 10 + Math.round((ratio - 1) / 9 * 5);
143
+ humanReadable = `Compensation fund: ${ratio.toFixed(1)}x order amount (covers ≥1 payout)`;
144
+ }
145
+ else {
146
+ score = Math.round(ratio * 10);
147
+ humanReadable = `Compensation fund: ${ratio.toFixed(1)}x order amount (insufficient)`;
148
+ }
149
+ return {
150
+ name: "fund_safety",
151
+ score: Math.min(maxScore, score),
152
+ maxScore,
153
+ description: `Fund ${fund.toString()} / typical order ${metrics.typicalOrderAmount.toString()} = ${ratio.toFixed(2)}x`,
154
+ humanReadable,
155
+ };
156
+ }
97
157
  const threshold = 1000000000000n;
98
158
  const ratio = Number(metrics.compensationFundBalance * 100n / threshold) / 100;
99
159
  const score = Math.min(maxScore, Math.round(ratio * maxScore));
@@ -101,8 +161,8 @@ function computeFundDimension(metrics) {
101
161
  name: "fund_safety",
102
162
  score,
103
163
  maxScore,
104
- description: `Compensation fund ${metrics.compensationFundBalance} smallest unit`,
105
- humanReadable: `Compensation fund: sufficient`,
164
+ description: `Compensation fund ${metrics.compensationFundBalance} smallest unit (absolute threshold fallback)`,
165
+ humanReadable: `Compensation fund: ${ratio.toFixed(2)}x absolute threshold`,
106
166
  };
107
167
  }
108
168
  function computeTransparencyDimension(metrics) {
@@ -0,0 +1,53 @@
1
+ import type { Project, ProjectObject, GraphEdge, ObjectCacheEntry, EvaluationType } from "@wowok/wowok";
2
+ import type { ReputationData } from "./graph-builder.js";
3
+ export interface CriterionScore {
4
+ name: string;
5
+ score: number;
6
+ weight: number;
7
+ rationale: string;
8
+ }
9
+ export interface EvaluationFinding {
10
+ criterion: string;
11
+ severity: "critical" | "warning" | "info";
12
+ message: string;
13
+ deduction: number;
14
+ }
15
+ export interface EvaluationResult {
16
+ evaluationType: EvaluationType;
17
+ score: number;
18
+ summary: string;
19
+ criterionScores: CriterionScore[];
20
+ findings: EvaluationFinding[];
21
+ strengths: string[];
22
+ needsLlm: boolean;
23
+ llmPrompt?: string;
24
+ evaluatedAt: number;
25
+ }
26
+ export interface EvaluationInput {
27
+ project: Project;
28
+ objects: ProjectObject[];
29
+ edges: GraphEdge[];
30
+ objectCache: Map<string, ObjectCacheEntry>;
31
+ reputation?: Map<string, ReputationData>;
32
+ }
33
+ export declare function runEvaluation(input: EvaluationInput, evaluationType: EvaluationType, llmPrompt?: string): EvaluationResult;
34
+ export interface ProjectComparisonEntry {
35
+ projectId: string;
36
+ projectName: string;
37
+ score: number | null;
38
+ summary: string | null;
39
+ evaluatedAt: number | null;
40
+ }
41
+ export interface ProjectComparison {
42
+ evaluationType: EvaluationType;
43
+ entries: ProjectComparisonEntry[];
44
+ ranking: ProjectComparisonEntry[];
45
+ bestProjectId: string | null;
46
+ }
47
+ export declare function compareProjects(entries: Array<{
48
+ projectId: string;
49
+ projectName: string;
50
+ score: number | null;
51
+ summary: string | null;
52
+ evaluatedAt: number | null;
53
+ }>, evaluationType: EvaluationType): ProjectComparison;