@wowok/agent-mcp 2.6.3 → 2.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -9
- package/dist/customer/customer-advice.d.ts +31 -0
- package/dist/customer/customer-advice.js +129 -0
- package/dist/customer/index.d.ts +2 -0
- package/dist/customer/index.js +2 -0
- package/dist/customer/info-puzzle.d.ts +8 -1
- package/dist/customer/info-puzzle.js +30 -5
- package/dist/customer/order-monitor.d.ts +2 -0
- package/dist/customer/order-monitor.js +3 -2
- package/dist/customer/post-purchase.d.ts +2 -0
- package/dist/customer/post-purchase.js +6 -5
- package/dist/customer/preorder-compare.d.ts +24 -0
- package/dist/customer/preorder-compare.js +34 -0
- package/dist/customer/reminder-system.d.ts +2 -0
- package/dist/customer/reminder-system.js +2 -1
- package/dist/customer/risk-assessment.js +4 -3
- package/dist/customer/types.d.ts +5 -0
- package/dist/examples/arbitration-dispute-create.json +41 -0
- package/dist/examples/arbitration-vote-weighted.json +35 -0
- package/dist/examples/arbitration-voting-guard-add.json +38 -0
- package/dist/examples/demand-present-service.json +33 -0
- package/dist/examples/gen-passport-verify-guard.json +48 -0
- package/dist/examples/guard-template-balance-check.json +36 -15
- package/dist/examples/guard-template-time-lock.json +33 -12
- package/dist/examples/insurance-guard-claim-timelock.json +75 -0
- package/dist/examples/insurance-guard-withdraw-allocation.json +96 -0
- package/dist/examples/insurance-machine-create-publish.json +75 -0
- package/dist/examples/insurance-service-allocators-publish.json +56 -0
- package/dist/examples/machine-multisig-threshold.json +86 -0
- package/dist/examples/machine-template-7node-rental.json +99 -94
- package/dist/examples/payment-scenario-bound.json +45 -0
- package/dist/examples/rental-ziroom-machine-create.json +126 -114
- package/dist/examples/rental-ziroom-permission-create.json +10 -3
- package/dist/examples/rental-ziroom-service-create.json +27 -18
- package/dist/examples/retail-adv-guard-customer-win-create.json +80 -0
- package/dist/examples/retail-adv-guard-messenger-proof-create.json +65 -0
- package/dist/examples/retail-adv-guard-reward-timeout-create.json +92 -0
- package/dist/examples/retail-adv-reward-guard-add.json +51 -0
- package/dist/examples/retail-myshop-allocation-activate.json +55 -0
- package/dist/examples/retail-myshop-arbitration-create.json +40 -0
- package/dist/examples/retail-myshop-contact-create.json +43 -0
- package/dist/examples/retail-myshop-order-create.json +56 -0
- package/dist/examples/retail-myshop-progress-operate.json +38 -0
- package/dist/examples/retail-myshop-reward-create.json +35 -0
- package/dist/examples/service-discount-issue.json +46 -0
- package/dist/examples/threebody-guard-create.json +56 -0
- package/dist/examples/threebody-machine-create.json +72 -0
- package/dist/examples/threebody-permission-create.json +38 -0
- package/dist/examples/threebody-service-allocators.json +49 -0
- package/dist/examples/travel-guard-time-lock.json +69 -0
- package/dist/examples/travel-guard-weather-oracle.json +70 -0
- package/dist/examples/travel-machine-create.json +136 -0
- package/dist/examples/travel-repository-create.json +47 -0
- package/dist/examples/travel-service-create.json +102 -0
- package/dist/examples/travel-treasury-create.json +34 -0
- package/dist/examples/treasury-deposit.json +37 -0
- package/dist/examples/treasury-withdraw.json +38 -0
- package/dist/extensions/business-modules.d.ts +49 -0
- package/dist/extensions/business-modules.js +287 -0
- package/dist/extensions/capability-manifest.js +192 -5
- package/dist/extensions/constraint-registry.js +3 -1
- package/dist/extensions/modes.js +10 -4
- package/dist/extensions/registry.d.ts +14 -9
- package/dist/extensions/registry.js +69 -14
- package/dist/extensions/types.d.ts +1 -0
- package/dist/knowledge/fund-layer.d.ts +67 -1
- package/dist/knowledge/fund-layer.js +561 -12
- package/dist/knowledge/guard-templates.d.ts +10 -0
- package/dist/knowledge/guard-templates.js +50 -0
- package/dist/knowledge/index.d.ts +2 -2
- package/dist/knowledge/index.js +2 -2
- package/dist/knowledge/machine-risk.js +4 -1
- package/dist/knowledge/progress-context.js +1 -1
- package/dist/knowledge/progress-ledger.js +3 -3
- package/dist/knowledge/progress-templates.js +1 -1
- package/dist/knowledge/progress-translation.js +1 -1
- package/dist/knowledge/safety-rules.d.ts +83 -1
- package/dist/knowledge/safety-rules.js +166 -2
- package/dist/knowledge/scenario-modes.d.ts +1 -1
- package/dist/knowledge/scenario-modes.js +13 -11
- package/dist/knowledge/template-registry.d.ts +48 -0
- package/dist/knowledge/template-registry.js +341 -0
- package/dist/knowledge/tool-constraints.js +6 -6
- package/dist/knowledge/tools-reference.js +11 -8
- package/dist/participation/merchant-interest.d.ts +32 -0
- package/dist/participation/merchant-interest.js +100 -0
- package/dist/participation/radar-core.d.ts +104 -0
- package/dist/participation/radar-core.js +269 -0
- package/dist/project/context-assembly.js +8 -0
- package/dist/project/edit-planner.js +27 -56
- package/dist/project/evaluation.d.ts +36 -0
- package/dist/project/evaluation.js +422 -56
- package/dist/project/game-theory.d.ts +43 -0
- package/dist/project/game-theory.js +177 -0
- package/dist/project/graph-builder.js +1 -0
- package/dist/project/handlers.d.ts +38 -0
- package/dist/project/handlers.js +65 -35
- package/dist/project/intent-analyzer.d.ts +71 -0
- package/dist/project/intent-analyzer.js +149 -0
- package/dist/project/machine-nodes.d.ts +2 -0
- package/dist/project/machine-nodes.js +36 -0
- package/dist/project/merchant-guide.d.ts +165 -0
- package/dist/project/merchant-guide.js +264 -0
- package/dist/project/mode-actions.d.ts +199 -0
- package/dist/project/mode-actions.js +309 -0
- package/dist/project/participation-radar.d.ts +18 -0
- package/dist/project/participation-radar.js +428 -0
- package/dist/project/pipeline-actions.d.ts +101 -0
- package/dist/project/pipeline-actions.js +109 -0
- package/dist/project/semantic-graph.d.ts +95 -0
- package/dist/project/semantic-graph.js +245 -0
- package/dist/schema/call/allocation.d.ts +11 -11
- package/dist/schema/call/allocation.js +11 -1
- package/dist/schema/call/arbitration.d.ts +21 -21
- package/dist/schema/call/arbitration.js +17 -9
- package/dist/schema/call/base.d.ts +2 -2
- package/dist/schema/call/base.js +1 -1
- package/dist/schema/call/bridge.d.ts +127 -127
- package/dist/schema/call/bridge.js +12 -12
- package/dist/schema/call/contact.d.ts +3 -3
- package/dist/schema/call/demand.d.ts +3 -3
- package/dist/schema/call/guard.d.ts +11 -11
- package/dist/schema/call/guard.js +1 -1
- package/dist/schema/call/machine.d.ts +216 -21
- package/dist/schema/call/machine.js +1 -1
- package/dist/schema/call/order.d.ts +7 -7
- package/dist/schema/call/payment.d.ts +3 -3
- package/dist/schema/call/permission.d.ts +3 -3
- package/dist/schema/call/personal.d.ts +337 -3
- package/dist/schema/call/personal.js +10 -0
- package/dist/schema/call/progress.d.ts +177 -9
- package/dist/schema/call/progress.js +7 -3
- package/dist/schema/call/proof.d.ts +6 -6
- package/dist/schema/call/repository.d.ts +3 -3
- package/dist/schema/call/reward.d.ts +57 -57
- package/dist/schema/call/semantic.js +41 -1
- package/dist/schema/call/service.d.ts +114 -114
- package/dist/schema/call/service.js +11 -2
- package/dist/schema/call/treasury.d.ts +57 -57
- package/dist/schema/messenger/index.js +4 -1
- package/dist/schema/operations.d.ts +713 -291
- package/dist/schema/operations.js +33 -0
- package/dist/schema/project/index.d.ts +4635 -100
- package/dist/schema/project/index.js +868 -1
- package/dist/schema/query/index.d.ts +363 -19
- package/dist/schema/query/index.js +25 -3
- package/dist/schema/schema-query/index.d.ts +13 -7
- package/dist/schema/schema-query/index.js +29 -5
- package/dist/schema/trust/index.d.ts +1012 -6
- package/dist/schema/trust/index.js +212 -11
- package/dist/schema/utils/skills-recommendation.js +1 -0
- package/dist/schema-query/index.d.ts +4 -1
- package/dist/schema-query/index.js +255 -1
- package/dist/schemas/bridge_operation.schema.json +14 -7
- package/dist/schemas/guard2file.schema.json +2 -0
- package/dist/schemas/index.json +1 -1
- package/dist/schemas/machineNode2file.schema.json +2 -0
- package/dist/schemas/messenger_operation.schema.json +1 -1
- package/dist/schemas/onchain_operations.schema.json +143 -15
- package/dist/schemas/onchain_operations_allocation.schema.json +2 -1
- package/dist/schemas/onchain_operations_arbitration.schema.json +7 -5
- package/dist/schemas/onchain_operations_contact.schema.json +1 -0
- package/dist/schemas/onchain_operations_demand.schema.json +1 -0
- package/dist/schemas/onchain_operations_gen_passport.schema.json +2 -0
- package/dist/schemas/onchain_operations_gen_proof.schema.json +2 -0
- package/dist/schemas/onchain_operations_guard.schema.json +578 -0
- package/dist/schemas/onchain_operations_machine.schema.json +1 -0
- package/dist/schemas/onchain_operations_order.schema.json +4 -3
- package/dist/schemas/onchain_operations_payment.schema.json +1 -0
- package/dist/schemas/onchain_operations_permission.schema.json +1 -0
- package/dist/schemas/onchain_operations_personal.schema.json +37 -0
- package/dist/schemas/onchain_operations_progress.schema.json +90 -3
- package/dist/schemas/onchain_operations_proof.schema.json +1 -0
- package/dist/schemas/onchain_operations_repository.schema.json +1 -0
- package/dist/schemas/onchain_operations_reward.schema.json +1 -0
- package/dist/schemas/onchain_operations_service.schema.json +4 -3
- package/dist/schemas/onchain_operations_treasury.schema.json +1 -0
- package/dist/schemas/project_operation.output.json +2243 -1
- package/dist/schemas/project_operation.schema.json +683 -1
- package/dist/schemas/query_toolkit.output.json +1 -1
- package/dist/schemas/query_toolkit.schema.json +37 -0
- package/dist/schemas/schema_query.output.json +1 -1
- package/dist/schemas/schema_query.schema.json +30 -5
- package/dist/schemas/trust_score.output.json +392 -1
- package/dist/schemas/trust_score.schema.json +275 -1
- package/dist/tools/handlers/onchain.js +73 -8
- package/dist/tools/handlers/project.js +46 -0
- package/dist/tools/handlers/query.js +117 -2
- package/dist/tools/handlers/schema-query.js +41 -0
- package/dist/tools/handlers/trust.js +192 -6
- package/dist/tools/index.js +52 -9
- package/dist/tools/wrap.js +194 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -46,28 +46,32 @@ wowok-skills init --target all # All 10 supported clients
|
|
|
46
46
|
|
|
47
47
|
#### Available Skills
|
|
48
48
|
|
|
49
|
-
**Always loaded** (
|
|
49
|
+
**Always loaded** (1 skill — foundational layer):
|
|
50
50
|
|
|
51
51
|
| Skill | Purpose |
|
|
52
52
|
|-------|---------|
|
|
53
|
-
| `wowok-tools` | MCP tool reference — 17 sub-tools, schema-gated execution, constraints |
|
|
54
|
-
| `wowok-safety` | Safety protocol — dry-run → confirm → execute, immutability rules |
|
|
55
53
|
| `wowok-output` | Output processing — address resolution, name mapping, data visualization |
|
|
56
54
|
|
|
57
|
-
**On-demand** (
|
|
55
|
+
**On-demand** (8 skills — loaded by context):
|
|
58
56
|
|
|
59
57
|
| Skill | Role | Purpose |
|
|
60
58
|
|-------|------|---------|
|
|
59
|
+
| `wowok-order` | 👤 Customer | Order lifecycle — due diligence, consensus, order creation, progress, arbitration |
|
|
61
60
|
| `wowok-provider` | 🏪 Provider | Service provider guide — create Service, Machine, Allocators, order fulfillment |
|
|
62
61
|
| `wowok-machine` | 🏪 Provider | Workflow design — state machines, node/pair/forward graph, publish lifecycle |
|
|
63
|
-
| `wowok-order` | 👤 Customer | Order lifecycle — due diligence, consensus, order creation, progress, arbitration |
|
|
64
62
|
| `wowok-arbitrator` | ⚖️ Arbitrator | Arbitration service — dispute resolution, weighted voting, fee management |
|
|
65
|
-
| `wowok-guard` | 🛠️ Shared | Guard design — programmable trust rules, 4 data sources, 33 constraints |
|
|
66
63
|
| `wowok-messenger` | 🛠️ Shared | Encrypted messaging — E2E communication, WTS evidence, anti-spam |
|
|
67
64
|
| `wowok-onboard` | 🆕 New User | First-touch onboarding — 10-round dialogue from zero to first published Service |
|
|
68
|
-
| `wowok-scenario` | 🛠️ Shared | Industry mode templates — freelance, rental, education, travel presets |
|
|
69
65
|
| `wowok-planner` | 🛠️ Shared | Planning — converts natural language intent into Object Dependency Graph (ODG) |
|
|
70
66
|
| `wowok-auditor` | 🛠️ Shared | Pre-publish audit — Guard completeness, Machine soundness, 32 audit checks |
|
|
71
|
-
| `wowok-distill` | 🏪 Provider | Distillation review — review AI-generated improvement proposals |
|
|
72
67
|
|
|
73
|
-
|
|
68
|
+
**Deprecated** (sunk to MCP knowledge layer — no longer installed as skills; their content is served by `schema_query` / `project_operation`):
|
|
69
|
+
|
|
70
|
+
| Skill | Replaced By |
|
|
71
|
+
|-------|-------------|
|
|
72
|
+
| `wowok-tools` | `schema_query action='get_tool_reference'` |
|
|
73
|
+
| `wowok-safety` | `schema_query action='get_safety_rules'` + runtime confirm-gate |
|
|
74
|
+
| `wowok-guard` | `schema_query action='get_guard_design_patterns'` |
|
|
75
|
+
| `wowok-scenario` | `project_operation` (recommend_industry / create_project) |
|
|
76
|
+
|
|
77
|
+
> **Tip:** `wowok-output` is always loaded. Add role-specific skills (`wowok-order`, `wowok-provider`, `wowok-arbitrator`) as needed. Guard design, safety rules, tool reference, and industry mode content are now served directly by the MCP server — no skill installation required.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type InfoPuzzle, type RiskScore, type UserPreferences, type Industry, type StrategyRecommendation, type PreferenceMatchResult, type ServiceForMatching, type IndustryRiskResult, type Reminder, type ReminderContext } from "./index.js";
|
|
2
|
+
export interface PreorderAdviceInput {
|
|
3
|
+
puzzle: InfoPuzzle;
|
|
4
|
+
risk?: RiskScore;
|
|
5
|
+
preferences?: UserPreferences;
|
|
6
|
+
industry?: Industry;
|
|
7
|
+
matching_overrides?: Partial<ServiceForMatching>;
|
|
8
|
+
reminder_overrides?: Partial<ReminderContext>;
|
|
9
|
+
max_strategies?: number;
|
|
10
|
+
max_reminders?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface ConfidenceScore {
|
|
13
|
+
score: number;
|
|
14
|
+
base: number;
|
|
15
|
+
user_adjustment: number;
|
|
16
|
+
preference_nudge: number;
|
|
17
|
+
explanation: string;
|
|
18
|
+
}
|
|
19
|
+
export interface PreorderAdvice {
|
|
20
|
+
service_id: string;
|
|
21
|
+
risk: RiskScore;
|
|
22
|
+
industry?: Industry;
|
|
23
|
+
strategies: StrategyRecommendation[];
|
|
24
|
+
preference_match?: PreferenceMatchResult;
|
|
25
|
+
industry_risks?: IndustryRiskResult;
|
|
26
|
+
reminders: Reminder[];
|
|
27
|
+
blocking_reminders: Reminder[];
|
|
28
|
+
confidence: ConfidenceScore;
|
|
29
|
+
summary: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function assemblePreorderAdvice(input: PreorderAdviceInput): PreorderAdvice;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { assessRisk, detectScenarios, recommendStrategy, matchServiceToPreferences, assessIndustryRisks, inferIndustry, generateReminders, getBlockingReminders, sortAndCapReminders, } from "./index.js";
|
|
2
|
+
import { registryDisplayHint } from "../knowledge/fund-layer.js";
|
|
3
|
+
export function assemblePreorderAdvice(input) {
|
|
4
|
+
const { puzzle } = input;
|
|
5
|
+
const risk = input.risk ?? assessRisk(puzzle);
|
|
6
|
+
const industry = input.industry ?? inferIndustry(puzzle);
|
|
7
|
+
const scenarios = detectScenarios(puzzle);
|
|
8
|
+
const strategies = scenarios
|
|
9
|
+
.slice(0, input.max_strategies ?? 3)
|
|
10
|
+
.map(s => recommendStrategy(s, { puzzle, prefs: input.preferences }));
|
|
11
|
+
let preferenceMatch;
|
|
12
|
+
if (input.preferences) {
|
|
13
|
+
const service = toMatchingService(puzzle, risk, input.matching_overrides);
|
|
14
|
+
preferenceMatch = matchServiceToPreferences(service, input.preferences);
|
|
15
|
+
}
|
|
16
|
+
let industryRisks;
|
|
17
|
+
if (industry) {
|
|
18
|
+
industryRisks = assessIndustryRisks(puzzle, industry);
|
|
19
|
+
}
|
|
20
|
+
const reminderCtx = buildReminderContext(puzzle, risk, input.reminder_overrides);
|
|
21
|
+
const reminders = sortAndCapReminders(generateReminders(reminderCtx))
|
|
22
|
+
.slice(0, input.max_reminders ?? 8);
|
|
23
|
+
const blocking = getBlockingReminders(reminders);
|
|
24
|
+
const confidence = computeConfidence(puzzle, risk, preferenceMatch);
|
|
25
|
+
return {
|
|
26
|
+
service_id: puzzle.service_id,
|
|
27
|
+
risk,
|
|
28
|
+
industry,
|
|
29
|
+
strategies,
|
|
30
|
+
preference_match: preferenceMatch,
|
|
31
|
+
industry_risks: industryRisks,
|
|
32
|
+
reminders,
|
|
33
|
+
blocking_reminders: blocking,
|
|
34
|
+
confidence,
|
|
35
|
+
summary: buildSummary(puzzle, risk, industry, strategies, preferenceMatch, blocking, confidence),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function toMatchingService(puzzle, risk, overrides) {
|
|
39
|
+
const basics = puzzle.service_basics;
|
|
40
|
+
const fund = puzzle.fund_safety;
|
|
41
|
+
const trust = puzzle.trust_signals;
|
|
42
|
+
const behavior = puzzle.merchant_behavior;
|
|
43
|
+
return {
|
|
44
|
+
service_id: puzzle.service_id,
|
|
45
|
+
price: basics.price_raw,
|
|
46
|
+
token_type: basics.token_type ?? "",
|
|
47
|
+
avg_market_price: puzzle.market_context?.avg_price,
|
|
48
|
+
merchant_order_history_count: behavior?.total_orders ?? 0,
|
|
49
|
+
merchant_age: behavior
|
|
50
|
+
? behavior.total_orders >= 50 ? "established" : "emerging"
|
|
51
|
+
: "unknown",
|
|
52
|
+
has_arbitration: (trust?.arbitration_count ?? 0) > 0,
|
|
53
|
+
has_compensation_fund: fund ? fund.compensation_ratio > 0 : false,
|
|
54
|
+
has_reward_activity: false,
|
|
55
|
+
has_discount: false,
|
|
56
|
+
risk_score: risk.total,
|
|
57
|
+
trust_score: trust?.trust_score ?? 50,
|
|
58
|
+
requires_messenger: false,
|
|
59
|
+
after_sales_support_level: trust?.has_messenger ? "full" : "minimal",
|
|
60
|
+
...overrides,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function buildReminderContext(puzzle, risk, overrides) {
|
|
64
|
+
const trust = puzzle.trust_signals;
|
|
65
|
+
const fund = puzzle.fund_safety;
|
|
66
|
+
const wf = puzzle.workflow_analysis;
|
|
67
|
+
return {
|
|
68
|
+
stage: "preorder",
|
|
69
|
+
service_id: puzzle.service_id,
|
|
70
|
+
review_count: trust?.review_total,
|
|
71
|
+
like_rate: trust?.like_rate,
|
|
72
|
+
avg_market_price: puzzle.market_context?.avg_price,
|
|
73
|
+
service_price: puzzle.service_basics.price_raw,
|
|
74
|
+
token: registryDisplayHint(puzzle.service_basics.token_type),
|
|
75
|
+
has_arbitration: (trust?.arbitration_count ?? 0) > 0,
|
|
76
|
+
has_compensation: fund ? fund.compensation_ratio > 0 : undefined,
|
|
77
|
+
compensation_ratio: fund?.compensation_ratio,
|
|
78
|
+
risk_score: risk.total,
|
|
79
|
+
risk_level: risk.level,
|
|
80
|
+
has_refund_path: wf?.has_refund_path,
|
|
81
|
+
has_messenger: trust?.has_messenger,
|
|
82
|
+
...overrides,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function computeConfidence(puzzle, risk, match) {
|
|
86
|
+
const base = Math.max(0, Math.min(100, 100 - risk.total));
|
|
87
|
+
const userAdj = puzzle.user_metrics?.adjustment ?? 0;
|
|
88
|
+
const prefNudge = match ? Math.round((match.score - 50) / 10) : 0;
|
|
89
|
+
const score = Math.max(0, Math.min(100, base + userAdj + prefNudge));
|
|
90
|
+
const parts = [`base ${base} (= 100 - risk ${risk.total})`];
|
|
91
|
+
if (userAdj !== 0)
|
|
92
|
+
parts.push(`your custom metrics ${userAdj > 0 ? "+" : ""}${userAdj}`);
|
|
93
|
+
if (prefNudge !== 0)
|
|
94
|
+
parts.push(`preference fit ${prefNudge > 0 ? "+" : ""}${prefNudge}`);
|
|
95
|
+
return {
|
|
96
|
+
score,
|
|
97
|
+
base,
|
|
98
|
+
user_adjustment: userAdj,
|
|
99
|
+
preference_nudge: prefNudge,
|
|
100
|
+
explanation: `Confidence ${score}/100 = ${parts.join(" ")}. ` +
|
|
101
|
+
`This is evidence aggregation, not advice — the decision is yours.`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function buildSummary(puzzle, risk, industry, strategies, match, blocking, confidence) {
|
|
105
|
+
const parts = [
|
|
106
|
+
`Order confidence ${confidence.score}/100 (risk ${risk.total}/100, level ${risk.level})` +
|
|
107
|
+
(industry ? ` for ${industry} service` : "") +
|
|
108
|
+
`. Information completeness ${Math.round(puzzle.completeness * 100)}%.`,
|
|
109
|
+
];
|
|
110
|
+
if (blocking.length > 0) {
|
|
111
|
+
parts.push(`⚠️ ${blocking.length} blocking concern(s): ${blocking.map(r => r.message).join("; ")}`);
|
|
112
|
+
}
|
|
113
|
+
if (risk.red_flags.length > 0) {
|
|
114
|
+
parts.push(`Red flags: ${risk.red_flags.slice(0, 3).join("; ")}.`);
|
|
115
|
+
}
|
|
116
|
+
if (strategies.length > 0) {
|
|
117
|
+
const top = strategies[0];
|
|
118
|
+
parts.push(`Key protection (${top.scenario}): ${top.strategy.user_strategy}`);
|
|
119
|
+
}
|
|
120
|
+
if (match) {
|
|
121
|
+
parts.push(match.mismatches.length > 0
|
|
122
|
+
? `Preference mismatches: ${match.mismatches.slice(0, 2).join("; ")}.`
|
|
123
|
+
: `Service matches your preferences (score ${match.score}/100).`);
|
|
124
|
+
}
|
|
125
|
+
if (puzzle.gaps.length > 0) {
|
|
126
|
+
parts.push(`Missing information: ${puzzle.gaps.join(", ")} — consider asking the merchant via Messenger before ordering.`);
|
|
127
|
+
}
|
|
128
|
+
return parts.join(" ");
|
|
129
|
+
}
|
package/dist/customer/index.d.ts
CHANGED
|
@@ -7,3 +7,5 @@ export { monitorOrder, sortAlerts, getCriticalAlerts, getActionableAlerts, summa
|
|
|
7
7
|
export { recommendStrategy, detectScenarios, flowMigrationStrategy, repeatGameStrategy, rightsProtectionStrategy, type StrategyContext, type StrategyRecommendation, } from "./order-strategy.js";
|
|
8
8
|
export { generatePostPurchaseAdvice, trackRefund, handleQualityIssue, handleMerchantUnreachable, arbitrationSupport, generateArbitrationTemplate, type PostPurchasePhase, type PostPurchaseContext, type PostPurchaseAction, } from "./post-purchase.js";
|
|
9
9
|
export { generateReminders, sortAndCapReminders, generateMultiStageReminders, isBlocking, getBlockingReminders, summarizeReminders, topReminders, type ReminderStage, type ReminderContext, } from "./reminder-system.js";
|
|
10
|
+
export { assemblePreorderAdvice, type PreorderAdviceInput, type PreorderAdvice, type ConfidenceScore, } from "./customer-advice.js";
|
|
11
|
+
export { buildPreorderComparison, type PreorderCompareRow, type PreorderComparison, } from "./preorder-compare.js";
|
package/dist/customer/index.js
CHANGED
|
@@ -7,3 +7,5 @@ export { monitorOrder, sortAlerts, getCriticalAlerts, getActionableAlerts, summa
|
|
|
7
7
|
export { recommendStrategy, detectScenarios, flowMigrationStrategy, repeatGameStrategy, rightsProtectionStrategy, } from "./order-strategy.js";
|
|
8
8
|
export { generatePostPurchaseAdvice, trackRefund, handleQualityIssue, handleMerchantUnreachable, arbitrationSupport, generateArbitrationTemplate, } from "./post-purchase.js";
|
|
9
9
|
export { generateReminders, sortAndCapReminders, generateMultiStageReminders, isBlocking, getBlockingReminders, summarizeReminders, topReminders, } from "./reminder-system.js";
|
|
10
|
+
export { assemblePreorderAdvice, } from "./customer-advice.js";
|
|
11
|
+
export { buildPreorderComparison, } from "./preorder-compare.js";
|
|
@@ -70,7 +70,10 @@ export declare function assembleMerchantBehavior(events: EventRaw[], orderHistor
|
|
|
70
70
|
status: string;
|
|
71
71
|
has_dispute: boolean;
|
|
72
72
|
is_repeat: boolean;
|
|
73
|
-
}
|
|
73
|
+
}>, reputation?: {
|
|
74
|
+
likes: number;
|
|
75
|
+
dislikes: number;
|
|
76
|
+
}): MerchantBehavior;
|
|
74
77
|
export declare function assembleMarketContext(similarServices: Array<{
|
|
75
78
|
price: bigint;
|
|
76
79
|
}>, currentPrice: bigint): MarketContext;
|
|
@@ -97,6 +100,10 @@ export interface PuzzleRawData {
|
|
|
97
100
|
has_dispute: boolean;
|
|
98
101
|
is_repeat: boolean;
|
|
99
102
|
}>;
|
|
103
|
+
merchant_reputation?: {
|
|
104
|
+
likes: number;
|
|
105
|
+
dislikes: number;
|
|
106
|
+
};
|
|
100
107
|
user_metrics_config?: UserMetricsConfig;
|
|
101
108
|
user_metrics_context?: Record<string, unknown>;
|
|
102
109
|
service_nesting_raw?: ServiceNestingRawData;
|
|
@@ -32,7 +32,7 @@ export function assembleWorkflowAnalysis(nodes, isPublished, isPaused, serviceRa
|
|
|
32
32
|
let hasMilestone = false;
|
|
33
33
|
let hasWonderNode = false;
|
|
34
34
|
let hasDisputeAntiPattern = false;
|
|
35
|
-
const antiPatternNodeRegex =
|
|
35
|
+
const antiPatternNodeRegex = /(^|_)(disputed?|refund(?:ed)?|arbitration|arb)(_|$)/i;
|
|
36
36
|
const wonderNodeRegex = /^(wonder|no_wonder|praise|complain|thumbs_up|thumbs_down|positive_review|negative_review)$/i;
|
|
37
37
|
const totalForwards = nodes.reduce((sum, n) => sum + (n.forwards?.length ?? 0), 0);
|
|
38
38
|
for (const node of nodes) {
|
|
@@ -172,7 +172,27 @@ export function assembleTrustSignals(service, reviews, trustScore, arbitrationOw
|
|
|
172
172
|
arbitration_permission_overlap: permissionOverlap,
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
|
-
|
|
175
|
+
const REPUTATION_MIN_VOTES = 3;
|
|
176
|
+
function toReputation(rep) {
|
|
177
|
+
const total = rep.likes + rep.dislikes;
|
|
178
|
+
return {
|
|
179
|
+
likes: rep.likes,
|
|
180
|
+
dislikes: rep.dislikes,
|
|
181
|
+
like_ratio: total > 0 ? rep.likes / total : 1,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function reputationRedFlags(rep) {
|
|
185
|
+
if (!rep)
|
|
186
|
+
return [];
|
|
187
|
+
const total = rep.likes + rep.dislikes;
|
|
188
|
+
if (total >= REPUTATION_MIN_VOTES && rep.like_ratio < 0.5) {
|
|
189
|
+
return ["reputation_negative"];
|
|
190
|
+
}
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
export function assembleMerchantBehavior(events, orderHistory, reputation) {
|
|
194
|
+
const rep = reputation ? toReputation(reputation) : undefined;
|
|
195
|
+
const repFlags = reputationRedFlags(rep);
|
|
176
196
|
if (orderHistory && orderHistory.length > 0) {
|
|
177
197
|
const total = orderHistory.length;
|
|
178
198
|
const completed = orderHistory.filter((o) => o.status === "completed").length;
|
|
@@ -193,7 +213,7 @@ export function assembleMerchantBehavior(events, orderHistory) {
|
|
|
193
213
|
else if (secondRate > firstRate * 1.15)
|
|
194
214
|
trend = "declining";
|
|
195
215
|
}
|
|
196
|
-
const redFlags = [];
|
|
216
|
+
const redFlags = [...repFlags];
|
|
197
217
|
if (disputeRate > 0.1)
|
|
198
218
|
redFlags.push("dispute_rate_high");
|
|
199
219
|
if (trend === "declining")
|
|
@@ -207,6 +227,7 @@ export function assembleMerchantBehavior(events, orderHistory) {
|
|
|
207
227
|
repeat_buyer_rate: repeatRate,
|
|
208
228
|
recent_trend: trend,
|
|
209
229
|
red_flags: redFlags,
|
|
230
|
+
reputation: rep,
|
|
210
231
|
};
|
|
211
232
|
}
|
|
212
233
|
const orderEvents = events.filter((e) => e.type.includes("Order") || e.type.includes("order"));
|
|
@@ -214,7 +235,7 @@ export function assembleMerchantBehavior(events, orderHistory) {
|
|
|
214
235
|
const total = orderEvents.length;
|
|
215
236
|
const disputes = disputeEvents.length;
|
|
216
237
|
const disputeRate = total > 0 ? disputes / total : 0;
|
|
217
|
-
const redFlags = [];
|
|
238
|
+
const redFlags = [...repFlags];
|
|
218
239
|
if (disputeRate > 0.1)
|
|
219
240
|
redFlags.push("dispute_rate_high");
|
|
220
241
|
return {
|
|
@@ -226,6 +247,7 @@ export function assembleMerchantBehavior(events, orderHistory) {
|
|
|
226
247
|
repeat_buyer_rate: 0,
|
|
227
248
|
recent_trend: "stable",
|
|
228
249
|
red_flags: redFlags,
|
|
250
|
+
reputation: rep,
|
|
229
251
|
};
|
|
230
252
|
}
|
|
231
253
|
export function assembleMarketContext(similarServices, currentPrice) {
|
|
@@ -284,7 +306,10 @@ export function assembleInfoPuzzle(serviceId, raw, depth = "evaluate") {
|
|
|
284
306
|
let merchantBehavior;
|
|
285
307
|
if (depth === "preorder" || depth === "monitor") {
|
|
286
308
|
if (raw.events || raw.order_history) {
|
|
287
|
-
merchantBehavior = assembleMerchantBehavior(raw.events ?? [], raw.order_history);
|
|
309
|
+
merchantBehavior = assembleMerchantBehavior(raw.events ?? [], raw.order_history, raw.merchant_reputation);
|
|
310
|
+
}
|
|
311
|
+
else if (raw.merchant_reputation) {
|
|
312
|
+
merchantBehavior = assembleMerchantBehavior([], undefined, raw.merchant_reputation);
|
|
288
313
|
}
|
|
289
314
|
else {
|
|
290
315
|
gaps.push("merchant_behavior");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RiskLevel } from "./types.js";
|
|
2
2
|
import { CUSTOMER_INTELLIGENCE_VERSION } from "./types.js";
|
|
3
|
+
import { type TokenDisplayHint } from "../knowledge/fund-layer.js";
|
|
3
4
|
export type AlertSeverity = "info" | "warning" | "critical";
|
|
4
5
|
export type AlertCategory = "progress_stall" | "compensation_drop" | "compensation_insufficient" | "messenger_timeout" | "user_action_required" | "review_window" | "arb_window" | "refund_received" | "anomaly";
|
|
5
6
|
export interface MonitorAlert {
|
|
@@ -30,6 +31,7 @@ export interface OrderSnapshot {
|
|
|
30
31
|
expected_progress_hours?: number;
|
|
31
32
|
order_amount?: bigint;
|
|
32
33
|
compensation_balance?: bigint;
|
|
34
|
+
token?: TokenDisplayHint;
|
|
33
35
|
has_arbitration?: boolean;
|
|
34
36
|
has_messenger?: boolean;
|
|
35
37
|
last_merchant_reply_at?: number;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CUSTOMER_INTELLIGENCE_VERSION } from "./types.js";
|
|
2
|
+
import { formatAmountText } from "../knowledge/fund-layer.js";
|
|
2
3
|
const DEFAULT_THRESHOLDS = {
|
|
3
4
|
progress_stall_hours: 0,
|
|
4
5
|
compensation_drop_ratio: 0.3,
|
|
@@ -118,7 +119,7 @@ function detectCompensationChange(cur, prev, t) {
|
|
|
118
119
|
category: "compensation_insufficient",
|
|
119
120
|
severity,
|
|
120
121
|
title: "Compensation fund coverage insufficient",
|
|
121
|
-
message: `Merchant compensation fund covers only ${Math.round(ratio * 100)}% of the order amount (required ${Math.round(t.compensation_coverage_min * 100)}%)`,
|
|
122
|
+
message: `Merchant compensation fund covers only ${Math.round(ratio * 100)}% of the order amount (required ${Math.round(t.compensation_coverage_min * 100)}%): fund ${formatAmountText(cur.compensation_balance, cur.token?.decimals, cur.token?.symbol)} vs order ${formatAmountText(cur.order_amount, cur.token?.decimals, cur.token?.symbol)}`,
|
|
122
123
|
action: "Require the merchant to top up the compensation fund before ordering, or negotiate higher coverage via Messenger",
|
|
123
124
|
timestamp: cur.now,
|
|
124
125
|
order_id: cur.order_id,
|
|
@@ -143,7 +144,7 @@ function detectCompensationChange(cur, prev, t) {
|
|
|
143
144
|
category: "compensation_drop",
|
|
144
145
|
severity,
|
|
145
146
|
title: "Compensation fund balance dropped significantly",
|
|
146
|
-
message: `Merchant compensation fund dropped from ${prevBal} to ${cur.compensation_balance} (down ${Math.round(dropRatio * 100)}%)`,
|
|
147
|
+
message: `Merchant compensation fund dropped from ${formatAmountText(prevBal, cur.token?.decimals, cur.token?.symbol)} to ${formatAmountText(cur.compensation_balance, cur.token?.decimals, cur.token?.symbol)} (down ${Math.round(dropRatio * 100)}%)`,
|
|
147
148
|
action: "Immediately ask the merchant for the reason; if it keeps dropping, the merchant may be processing payouts for other orders, which is a risk",
|
|
148
149
|
timestamp: cur.now,
|
|
149
150
|
order_id: cur.order_id,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { InfoPuzzle } from "./types.js";
|
|
2
2
|
import { CUSTOMER_INTELLIGENCE_VERSION } from "./types.js";
|
|
3
|
+
import { type TokenDisplayHint } from "../knowledge/fund-layer.js";
|
|
3
4
|
export type PostPurchasePhase = "refund_tracking" | "quality_issue" | "merchant_unreachable" | "arbitration_support";
|
|
4
5
|
export interface PostPurchaseContext {
|
|
5
6
|
phase: PostPurchasePhase;
|
|
@@ -8,6 +9,7 @@ export interface PostPurchaseContext {
|
|
|
8
9
|
puzzle?: InfoPuzzle;
|
|
9
10
|
order_amount?: bigint;
|
|
10
11
|
refunded_amount?: bigint;
|
|
12
|
+
token?: TokenDisplayHint;
|
|
11
13
|
wip_hash?: string;
|
|
12
14
|
original_wip_hash?: string;
|
|
13
15
|
last_merchant_reply_at?: number;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CUSTOMER_INTELLIGENCE_VERSION } from "./types.js";
|
|
2
|
+
import { formatAmountText } from "../knowledge/fund-layer.js";
|
|
2
3
|
export function generatePostPurchaseAdvice(ctx) {
|
|
3
4
|
switch (ctx.phase) {
|
|
4
5
|
case "refund_tracking":
|
|
@@ -21,7 +22,7 @@ export function trackRefund(ctx) {
|
|
|
21
22
|
phase: "refund_tracking",
|
|
22
23
|
priority: "info",
|
|
23
24
|
title: "Refund complete",
|
|
24
|
-
message: `✅ Order ${ctx.order_id} refund fully received (${refunded
|
|
25
|
+
message: `✅ Order ${ctx.order_id} refund fully received (${formatAmountText(refunded, ctx.token?.decimals, ctx.token?.symbol)})`,
|
|
25
26
|
next_step: "You can close post-purchase tracking; recommend submitting an order review",
|
|
26
27
|
});
|
|
27
28
|
return actions;
|
|
@@ -33,7 +34,7 @@ export function trackRefund(ctx) {
|
|
|
33
34
|
phase: "refund_tracking",
|
|
34
35
|
priority: "required",
|
|
35
36
|
title: "Refund incomplete",
|
|
36
|
-
message: `⚠️ Order ${ctx.order_id} only refunded ${refunded}
|
|
37
|
+
message: `⚠️ Order ${ctx.order_id} only refunded ${formatAmountText(refunded, ctx.token?.decimals, ctx.token?.symbol)} of ${formatAmountText(orderAmount, ctx.token?.decimals, ctx.token?.symbol)}; the difference of ${formatAmountText(diff, ctx.token?.decimals, ctx.token?.symbol)} has not been received`,
|
|
37
38
|
next_step: "Urge the merchant via Messenger to make up the difference, or initiate arbitration to recover it",
|
|
38
39
|
tool: "messenger_send",
|
|
39
40
|
});
|
|
@@ -284,7 +285,7 @@ export function generateArbitrationTemplate(ctx) {
|
|
|
284
285
|
descriptionParts.push(`Dispute type: ${phaseLabel}`);
|
|
285
286
|
switch (ctx.phase) {
|
|
286
287
|
case "refund_tracking":
|
|
287
|
-
descriptionParts.push(`Dispute summary: The merchant did not refund as required. Order amount ${ctx.order_amount
|
|
288
|
+
descriptionParts.push(`Dispute summary: The merchant did not refund as required. Order amount ${ctx.order_amount !== undefined ? formatAmountText(ctx.order_amount, ctx.token?.decimals, ctx.token?.symbol) : "unknown"}, refunded ${formatAmountText(ctx.refunded_amount ?? 0n, ctx.token?.decimals, ctx.token?.symbol)}.`);
|
|
288
289
|
break;
|
|
289
290
|
case "quality_issue":
|
|
290
291
|
descriptionParts.push(`Dispute summary: The deliverable has quality issues. Original WIP hash: ${ctx.original_wip_hash ?? "unknown"}, current: ${ctx.wip_hash ?? "unknown"}.`);
|
|
@@ -335,9 +336,9 @@ function buildClaim(ctx) {
|
|
|
335
336
|
const refunded = ctx.refunded_amount ?? 0n;
|
|
336
337
|
const diff = orderAmount - refunded;
|
|
337
338
|
if (refunded === 0n) {
|
|
338
|
-
return `Request the arbitrator to order a full refund (${orderAmount
|
|
339
|
+
return `Request the arbitrator to order a full refund (${formatAmountText(orderAmount, ctx.token?.decimals, ctx.token?.symbol)}).`;
|
|
339
340
|
}
|
|
340
|
-
return `Request the arbitrator to order the merchant to make up the refund difference (${diff
|
|
341
|
+
return `Request the arbitrator to order the merchant to make up the refund difference (${formatAmountText(diff, ctx.token?.decimals, ctx.token?.symbol)}).`;
|
|
341
342
|
}
|
|
342
343
|
case "quality_issue":
|
|
343
344
|
return "Request the arbitrator to order the merchant to redeliver a deliverable that meets the agreement, or to fully refund.";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface PreorderCompareRow {
|
|
2
|
+
service_id: string;
|
|
3
|
+
service_name: string;
|
|
4
|
+
error?: string;
|
|
5
|
+
industry?: string;
|
|
6
|
+
confidence?: number;
|
|
7
|
+
risk_total?: number;
|
|
8
|
+
risk_level?: string;
|
|
9
|
+
trust_score?: number;
|
|
10
|
+
trust_level?: string;
|
|
11
|
+
preference_match?: number;
|
|
12
|
+
reputation_like_ratio?: number;
|
|
13
|
+
reputation_votes?: number;
|
|
14
|
+
red_flags_count?: number;
|
|
15
|
+
blocking_reminders_count?: number;
|
|
16
|
+
info_gaps_count?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface PreorderComparison {
|
|
19
|
+
rows: PreorderCompareRow[];
|
|
20
|
+
best_per_metric: Record<string, string[]>;
|
|
21
|
+
evaluated_metrics: string[];
|
|
22
|
+
note: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function buildPreorderComparison(rows: PreorderCompareRow[]): PreorderComparison;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const METRICS = [
|
|
2
|
+
{ key: "confidence", name: "confidence", direction: "high" },
|
|
3
|
+
{ key: "risk_total", name: "risk_total", direction: "low" },
|
|
4
|
+
{ key: "trust_score", name: "trust_score", direction: "high" },
|
|
5
|
+
{ key: "preference_match", name: "preference_match", direction: "high" },
|
|
6
|
+
{ key: "reputation_like_ratio", name: "reputation_like_ratio", direction: "high" },
|
|
7
|
+
{ key: "red_flags_count", name: "red_flags_count", direction: "low" },
|
|
8
|
+
{ key: "blocking_reminders_count", name: "blocking_reminders_count", direction: "low" },
|
|
9
|
+
{ key: "info_gaps_count", name: "info_gaps_count", direction: "low" },
|
|
10
|
+
];
|
|
11
|
+
const NEUTRALITY_NOTE = "Per-metric bests only — NO overall ranking is computed. " +
|
|
12
|
+
"Metric weights are the buyer's own: re-run with user_metrics to change what matters. " +
|
|
13
|
+
"A service 'best' on one metric may be worst on another; the decision is yours.";
|
|
14
|
+
export function buildPreorderComparison(rows) {
|
|
15
|
+
const best_per_metric = {};
|
|
16
|
+
const evaluated_metrics = [];
|
|
17
|
+
for (const m of METRICS) {
|
|
18
|
+
const candidates = rows.filter((r) => !r.error && typeof r[m.key] === "number");
|
|
19
|
+
if (candidates.length < 2)
|
|
20
|
+
continue;
|
|
21
|
+
const values = candidates.map((r) => r[m.key]);
|
|
22
|
+
const best = m.direction === "high" ? Math.max(...values) : Math.min(...values);
|
|
23
|
+
best_per_metric[m.name] = candidates
|
|
24
|
+
.filter((r) => r[m.key] === best)
|
|
25
|
+
.map((r) => r.service_id);
|
|
26
|
+
evaluated_metrics.push(m.name);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
rows,
|
|
30
|
+
best_per_metric,
|
|
31
|
+
evaluated_metrics,
|
|
32
|
+
note: NEUTRALITY_NOTE,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Reminder, RiskLevel } from "./types.js";
|
|
2
2
|
import { CUSTOMER_INTELLIGENCE_VERSION } from "./types.js";
|
|
3
|
+
import { type TokenDisplayHint } from "../knowledge/fund-layer.js";
|
|
3
4
|
export type ReminderStage = "browse" | "evaluate" | "preorder" | "in_progress" | "complete" | "after_sale";
|
|
4
5
|
export interface ReminderContext {
|
|
5
6
|
stage: ReminderStage;
|
|
@@ -13,6 +14,7 @@ export interface ReminderContext {
|
|
|
13
14
|
has_compensation?: boolean;
|
|
14
15
|
compensation_balance?: bigint;
|
|
15
16
|
compensation_ratio?: number;
|
|
17
|
+
token?: TokenDisplayHint;
|
|
16
18
|
risk_score?: number;
|
|
17
19
|
risk_level?: RiskLevel;
|
|
18
20
|
has_refund_path?: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CUSTOMER_INTELLIGENCE_VERSION } from "./types.js";
|
|
2
|
+
import { formatAmountText } from "../knowledge/fund-layer.js";
|
|
2
3
|
const REMINDER_RULES = [
|
|
3
4
|
{
|
|
4
5
|
id: "browse_reviews_summary",
|
|
@@ -108,7 +109,7 @@ const REMINDER_RULES = [
|
|
|
108
109
|
id: "preorder_payment_confirm",
|
|
109
110
|
stage: "preorder",
|
|
110
111
|
priority: "required",
|
|
111
|
-
message: (ctx) => `🔔 About to pay ${ctx.service_price
|
|
112
|
+
message: (ctx) => `🔔 About to pay ${formatAmountText(ctx.service_price ?? 0n, ctx.token?.decimals, ctx.token?.symbol)} to the escrow account, please confirm`,
|
|
112
113
|
applies: (ctx) => ctx.service_price !== undefined,
|
|
113
114
|
dedup_key: "payment_confirm",
|
|
114
115
|
},
|
|
@@ -245,7 +245,8 @@ function assessBehaviorRisk(puzzle) {
|
|
|
245
245
|
passed: trendPassed,
|
|
246
246
|
advice: trendAdvice,
|
|
247
247
|
});
|
|
248
|
-
const
|
|
248
|
+
const hasOrders = beh != null && beh.total_orders > 0;
|
|
249
|
+
const completionPassed = hasOrders ? beh.completed_rate >= 0.85 : true;
|
|
249
250
|
checks.push({
|
|
250
251
|
id: "behavior_completion_rate",
|
|
251
252
|
dimension: "behavior",
|
|
@@ -254,7 +255,7 @@ function assessBehaviorRisk(puzzle) {
|
|
|
254
255
|
passed: completionPassed,
|
|
255
256
|
advice: completionPassed ? undefined : `🔴 Completion rate is only ${Math.round((beh?.completed_rate ?? 0) * 100)}%: a higher-than-average share of orders end in failure.`,
|
|
256
257
|
});
|
|
257
|
-
const disputeOk =
|
|
258
|
+
const disputeOk = hasOrders ? beh.dispute_rate <= 0.1 : true;
|
|
258
259
|
checks.push({
|
|
259
260
|
id: "behavior_low_dispute",
|
|
260
261
|
dimension: "behavior",
|
|
@@ -263,7 +264,7 @@ function assessBehaviorRisk(puzzle) {
|
|
|
263
264
|
passed: disputeOk,
|
|
264
265
|
advice: disputeOk ? undefined : `⚠️ Dispute rate is ${Math.round((beh?.dispute_rate ?? 0) * 100)}%: above the industry average.`,
|
|
265
266
|
});
|
|
266
|
-
const arbLossOk =
|
|
267
|
+
const arbLossOk = hasOrders ? beh.arb_loss_rate <= 0.3 : true;
|
|
267
268
|
checks.push({
|
|
268
269
|
id: "behavior_arb_loss",
|
|
269
270
|
dimension: "behavior",
|
package/dist/customer/types.d.ts
CHANGED
|
@@ -73,6 +73,11 @@ export interface MerchantBehavior {
|
|
|
73
73
|
repeat_buyer_rate: number;
|
|
74
74
|
recent_trend: "improving" | "stable" | "declining";
|
|
75
75
|
red_flags: string[];
|
|
76
|
+
reputation?: {
|
|
77
|
+
likes: number;
|
|
78
|
+
dislikes: number;
|
|
79
|
+
like_ratio: number;
|
|
80
|
+
};
|
|
76
81
|
}
|
|
77
82
|
export interface MarketContext {
|
|
78
83
|
similar_services_count: number;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Open Dispute on an Order (Arbitration Case Creation)",
|
|
3
|
+
"description": "Customer opens a dispute on order myshop_order_v1 via the MyShop Arbitration object, paying the dispute fee and naming the new Arb case object for later vote/verdict operations.",
|
|
4
|
+
"tags": ["arbitration", "dispute", "order", "retail"],
|
|
5
|
+
"industry": "retail",
|
|
6
|
+
"operation_type": "arbitration",
|
|
7
|
+
"source": "constructed under T-09 authorization; grounded in DisputeSchema + SDK arbitration.ts dispute flow + arb.move dispute_imp — schema-validated, not chain-verified",
|
|
8
|
+
"verified": false,
|
|
9
|
+
"network": "testnet",
|
|
10
|
+
"call": {
|
|
11
|
+
"tool": "onchain_operations",
|
|
12
|
+
"operation_type": "arbitration",
|
|
13
|
+
"data": {
|
|
14
|
+
"object": "myshop_arbitration_v2",
|
|
15
|
+
"dispute": {
|
|
16
|
+
"order": "myshop_order_v1",
|
|
17
|
+
"description": "Toy arrived damaged; requesting refund per service promise.",
|
|
18
|
+
"proposition": [
|
|
19
|
+
"Full refund to customer",
|
|
20
|
+
"Partial refund 50%",
|
|
21
|
+
"No refund — service delivered as promised"
|
|
22
|
+
],
|
|
23
|
+
"fee": { "balance": 5000000 },
|
|
24
|
+
"namedArb": { "name": "myshop_dispute_v1" }
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"env": {
|
|
28
|
+
"network": "testnet",
|
|
29
|
+
"no_cache": true,
|
|
30
|
+
"confirmed": true
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"notes": [
|
|
34
|
+
"PREREQUISITES (SDK-validated client-side): the Arbitration must NOT be paused (bPaused=false — new Arbitrations are created paused; unpause first via {object:'myshop_arbitration_v2', pause:false}); the Order must not be already claimed (claimed_by empty) and must have fewer than MAX_DISPUTE_COUNT disputes.",
|
|
35
|
+
"fee uses CoinParam {balance: <smallest unit>} — 5000000 = 0.005 WOW (9 decimals). Contract asserts fee >= arbitration.fee (E_FEE_NOT_ENOUGH); excess is split and returned to the sender.",
|
|
36
|
+
"proposition is the list of options voters choose between; votes reference propositions by 0-BASED INDEX (0='Full refund', 1='Partial 50%', 2='No refund'). Order matters and is immutable once the Arb is created.",
|
|
37
|
+
"namedArb names the NEW Arb (arbitration case) object — strongly recommended: subsequent confirm/vote/arbitration calls reference the case by this name ('myshop_dispute_v1') instead of a raw address.",
|
|
38
|
+
"If the Arbitration has a usage_guard configured, the dispute caller must pass that Guard (SDK auto-adds it to the passport verification list). This example assumes no usage_guard.",
|
|
39
|
+
"The Arb case is created in a pre-voting state; the arbitrator next calls confirm with a voting_deadline to open the voting window."
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Vote on Dispute Propositions via Voting Guard",
|
|
3
|
+
"description": "Eligible arbitrator casts a weighted vote for proposition 0 (full refund) on dispute case myshop_dispute_v1, verifying through the configured voting_guard.",
|
|
4
|
+
"tags": ["arbitration", "vote", "dispute", "guard"],
|
|
5
|
+
"industry": "retail",
|
|
6
|
+
"operation_type": "arbitration",
|
|
7
|
+
"source": "constructed under T-09 authorization; grounded in VoteSchema + SDK arbitration.ts vote flow + arb.move vote (re-vote replaces) — schema-validated, not chain-verified",
|
|
8
|
+
"verified": false,
|
|
9
|
+
"network": "testnet",
|
|
10
|
+
"call": {
|
|
11
|
+
"tool": "onchain_operations",
|
|
12
|
+
"operation_type": "arbitration",
|
|
13
|
+
"data": {
|
|
14
|
+
"object": "myshop_arbitration_v2",
|
|
15
|
+
"vote": {
|
|
16
|
+
"arb": "myshop_dispute_v1",
|
|
17
|
+
"votes": [0],
|
|
18
|
+
"voting_guard": "arbitrator_eligibility_guard"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"env": {
|
|
22
|
+
"network": "testnet",
|
|
23
|
+
"no_cache": true,
|
|
24
|
+
"confirmed": true
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"notes": [
|
|
28
|
+
"votes elements are PROPOSITION INDICES (u8, 0-based) into the dispute's proposition list — [0] means 'agree with proposition 0 (Full refund)'. Voting for multiple propositions at once is allowed (e.g. [0,1]); each listed index receives the voter's full weight. An out-of-range index aborts with E_PROPOSITION_NOT_FOUND.",
|
|
29
|
+
"RE-VOTING REPLACES: a second vote by the same voter removes the old weight from previously voted indices and applies it to the new set (arb.move vote). There is no separate 'unvote' operation.",
|
|
30
|
+
"SDK REQUIREMENT (call/arbitration.ts L264-273): when voting on an EXISTING Arbitration through the SDK/MCP path, vote.voting_guard is effectively REQUIRED — the SDK adds it to the passport verification list and errors 'vote.voting_guard invalid' if omitted, even though the MCP schema marks it optional. Always provide it.",
|
|
31
|
+
"PREREQUISITES: (1) the Arb case must be in Status_Voting — the arbitrator has called confirm with a voting_deadline; (2) voting must be within the deadline (E_VOTING_DEADLINE_PASSED); (3) the guard must be in the Arbitration's voting_guard list (see arbitration-voting-guard-add example) and the voter must pass its verification.",
|
|
32
|
+
"Weight resolution (arbitration.move vote_with_voting_guard): {FixedValue: n} → weight n; {GuardIdentifier: i} → weight read from the voter's passport submission at that Guard table index.",
|
|
33
|
+
"Voting concludes when the arbitrator calls arbitration (verdict) with an indemnity amount; the verdict only RECORDS the indemnity on the Arb — the customer then claims compensation from the Service's compensation_fund via order compensation_claim."
|
|
34
|
+
]
|
|
35
|
+
}
|