@wowok/agent-mcp 3.1.3 → 3.1.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.
- package/dist/config/config-audit.spec.d.ts +1 -0
- package/dist/config/config-audit.spec.js +1 -0
- package/dist/config/exposure.d.ts +108 -0
- package/dist/config/exposure.js +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +1 -1
- package/dist/config/judgment.d.ts +1228 -0
- package/dist/config/judgment.js +1 -0
- package/dist/config/judgment.spec.d.ts +1 -0
- package/dist/config/judgment.spec.js +1 -0
- package/dist/config/rule-engine.d.ts +299 -0
- package/dist/config/rule-engine.js +1 -0
- package/dist/config/rule-engine.spec.d.ts +1 -0
- package/dist/config/rule-engine.spec.js +1 -0
- package/dist/config/severity.d.ts +7 -0
- package/dist/config/severity.js +1 -0
- package/dist/customer/order-monitor.d.ts +3 -1
- package/dist/customer/order-monitor.js +1 -1
- package/dist/evaluation/acceptance.d.ts +1 -0
- package/dist/evaluation/acceptance.js +1 -1
- package/dist/evaluation/arbitration-game.js +1 -1
- package/dist/evaluation/builtins/demand-match.js +1 -1
- package/dist/evaluation/builtins/graph-service.js +1 -1
- package/dist/evaluation/builtins/graph-service.spec.js +1 -1
- package/dist/evaluation/engine.js +1 -1
- package/dist/evaluation/game-strategy.d.ts +2 -2
- package/dist/evaluation/game-strategy.js +1 -1
- package/dist/evaluation/match-operation.d.ts +2 -2
- package/dist/evaluation/match-operation.js +1 -1
- package/dist/evaluation/standards.d.ts +3 -25
- package/dist/evaluation/standards.js +1 -1
- package/dist/evaluation/types.d.ts +2 -1
- package/dist/experience/realtime-feedback.js +1 -1
- package/dist/extensions/business-modules.js +1 -1
- package/dist/extensions/custom-registry-file.js +1 -1
- package/dist/extensions/industry-audit.spec.d.ts +1 -0
- package/dist/extensions/industry-audit.spec.js +1 -0
- package/dist/extensions/industry-layers.d.ts +8 -0
- package/dist/extensions/industry-layers.js +1 -1
- package/dist/extensions/industry-pack.d.ts +2 -0
- package/dist/extensions/industry-pack.js +1 -1
- package/dist/extensions/mode-evaluator.js +1 -1
- package/dist/extensions/modes.js +1 -1
- package/dist/graph/onchain/analyze.d.ts +3 -1
- package/dist/graph/onchain/analyze.js +1 -1
- package/dist/graph/onchain/analyze.spec.js +1 -1
- package/dist/graph/onchain/edge-schema.d.ts +1 -0
- package/dist/graph/onchain/edge-schema.js +1 -1
- package/dist/graph/onchain/expand.js +1 -1
- package/dist/graph/onchain/exploration.d.ts +28 -0
- package/dist/graph/onchain/exploration.js +1 -0
- package/dist/graph/onchain/exploration.spec.d.ts +1 -0
- package/dist/graph/onchain/exploration.spec.js +1 -0
- package/dist/graph/onchain/exposure.d.ts +18 -0
- package/dist/graph/onchain/exposure.js +1 -0
- package/dist/graph/onchain/exposure.spec.d.ts +1 -0
- package/dist/graph/onchain/exposure.spec.js +1 -0
- package/dist/graph/onchain/graph-policy.spec.d.ts +1 -0
- package/dist/graph/onchain/graph-policy.spec.js +1 -0
- package/dist/graph/onchain/index.d.ts +6 -0
- package/dist/graph/onchain/index.js +1 -1
- package/dist/graph/onchain/interest.js +1 -1
- package/dist/graph/onchain/interest.spec.js +1 -1
- package/dist/graph/onchain/names.js +1 -1
- package/dist/graph/onchain/names.spec.js +1 -1
- package/dist/graph/onchain/policy.d.ts +8 -0
- package/dist/graph/onchain/policy.js +1 -0
- package/dist/graph/onchain/proposal-graph.js +1 -1
- package/dist/graph/onchain/proposal-graph.spec.js +1 -1
- package/dist/graph/onchain/synthesis.d.ts +20 -0
- package/dist/graph/onchain/synthesis.js +1 -0
- package/dist/graph/onchain/synthesis.spec.d.ts +1 -0
- package/dist/graph/onchain/synthesis.spec.js +1 -0
- package/dist/graph/onchain/types.d.ts +11 -1
- package/dist/keeper/keeper.spec.js +1 -1
- package/dist/knowledge/alloc-audit-policy.spec.d.ts +1 -0
- package/dist/knowledge/alloc-audit-policy.spec.js +1 -0
- package/dist/knowledge/allocation-ledger.js +1 -1
- package/dist/knowledge/allocation-puzzle.d.ts +1 -1
- package/dist/knowledge/allocation-puzzle.js +1 -1
- package/dist/knowledge/allocation-risk.d.ts +4 -1
- package/dist/knowledge/allocation-risk.js +1 -1
- package/dist/knowledge/allocation-templates.js +1 -1
- package/dist/knowledge/arb-risk.d.ts +6 -5
- package/dist/knowledge/arb-risk.js +1 -1
- package/dist/knowledge/arbitration-ledger.d.ts +4 -4
- package/dist/knowledge/arbitration-ledger.js +1 -1
- package/dist/knowledge/arbitration-puzzle.d.ts +1 -1
- package/dist/knowledge/arbitration-puzzle.js +1 -1
- package/dist/knowledge/arbitration-risk.d.ts +4 -1
- package/dist/knowledge/arbitration-risk.js +1 -1
- package/dist/knowledge/arbitration-templates.js +1 -1
- package/dist/knowledge/baselines/judgment-baselines.json +289 -0
- package/dist/knowledge/baselines/risk-baselines.spec.js +1 -1
- package/dist/knowledge/baselines/rules/alloc_audit.json +290 -0
- package/dist/knowledge/baselines/rules/allocation.json +492 -0
- package/dist/knowledge/baselines/rules/arb.json +155 -0
- package/dist/knowledge/baselines/rules/arbitration.json +366 -0
- package/dist/knowledge/baselines/rules/bridge.json +197 -0
- package/dist/knowledge/baselines/rules/contact.json +152 -0
- package/dist/knowledge/baselines/rules/demand.json +158 -0
- package/dist/knowledge/baselines/rules/graph.json +453 -0
- package/dist/knowledge/baselines/rules/guard.json +981 -0
- package/dist/knowledge/baselines/rules/machine.json +706 -0
- package/dist/knowledge/baselines/rules/order.json +549 -0
- package/dist/knowledge/baselines/rules/payment.json +205 -0
- package/dist/knowledge/baselines/rules/permission.json +330 -0
- package/dist/knowledge/baselines/rules/personal.json +139 -0
- package/dist/knowledge/baselines/rules/progress.json +346 -0
- package/dist/knowledge/baselines/rules/proof.json +158 -0
- package/dist/knowledge/baselines/rules/registrar.json +159 -0
- package/dist/knowledge/baselines/rules/repository.json +244 -0
- package/dist/knowledge/baselines/rules/resource.json +117 -0
- package/dist/knowledge/baselines/rules/reward.json +471 -0
- package/dist/knowledge/baselines/rules/service.json +595 -0
- package/dist/knowledge/baselines/rules/treasury.json +440 -0
- package/dist/knowledge/baselines/rules/util.json +101 -0
- package/dist/knowledge/bridge-risk.d.ts +6 -5
- package/dist/knowledge/bridge-risk.js +1 -1
- package/dist/knowledge/builtin-templates.d.ts +26 -0
- package/dist/knowledge/builtin-templates.js +1 -0
- package/dist/knowledge/contact-risk.d.ts +6 -5
- package/dist/knowledge/contact-risk.js +1 -1
- package/dist/knowledge/demand-risk.d.ts +6 -5
- package/dist/knowledge/demand-risk.js +1 -1
- package/dist/knowledge/event-semantics.js +1 -1
- package/dist/knowledge/facts-sync.spec.d.ts +1 -0
- package/dist/knowledge/facts-sync.spec.js +1 -0
- package/dist/knowledge/getting-started.js +1 -1
- package/dist/knowledge/guard-design-patterns.js +1 -1
- package/dist/knowledge/guard-field-cognition.d.ts +1 -1
- package/dist/knowledge/guard-field-cognition.js +1 -1
- package/dist/knowledge/guard-ledger.js +1 -1
- package/dist/knowledge/guard-risk.d.ts +4 -1
- package/dist/knowledge/guard-risk.js +1 -1
- package/dist/knowledge/guard-templates.js +1 -1
- package/dist/knowledge/guard-translation.js +1 -1
- package/dist/knowledge/index.d.ts +10 -2
- package/dist/knowledge/index.js +1 -1
- package/dist/knowledge/industry-registry.js +1 -1
- package/dist/knowledge/industry-strategy.js +1 -1
- package/dist/knowledge/jsonrpc-enum.js +1 -1
- package/dist/knowledge/machine-ledger.js +1 -1
- package/dist/knowledge/machine-risk.d.ts +4 -1
- package/dist/knowledge/machine-risk.js +1 -1
- package/dist/knowledge/machine-templates.js +1 -1
- package/dist/knowledge/machine-translation.js +1 -1
- package/dist/knowledge/migration-preflight.js +1 -1
- package/dist/knowledge/operation-dictionary.js +1 -1
- package/dist/knowledge/order-ledger.js +1 -1
- package/dist/knowledge/order-puzzle.d.ts +3 -3
- package/dist/knowledge/order-puzzle.js +1 -1
- package/dist/knowledge/order-risk.d.ts +6 -3
- package/dist/knowledge/order-risk.js +1 -1
- package/dist/knowledge/order-templates.js +1 -1
- package/dist/knowledge/passport-ledger.js +1 -1
- package/dist/knowledge/passport-templates.js +1 -1
- package/dist/knowledge/payment-risk.d.ts +8 -6
- package/dist/knowledge/payment-risk.js +1 -1
- package/dist/knowledge/payment-tracker.js +1 -1
- package/dist/knowledge/permission-ledger.js +1 -1
- package/dist/knowledge/permission-puzzle.d.ts +12 -12
- package/dist/knowledge/permission-puzzle.js +1 -1
- package/dist/knowledge/permission-risk.d.ts +4 -7
- package/dist/knowledge/permission-risk.js +1 -1
- package/dist/knowledge/permission-templates.js +1 -1
- package/dist/knowledge/personal-risk.d.ts +6 -5
- package/dist/knowledge/personal-risk.js +1 -1
- package/dist/knowledge/progress-ledger.js +1 -1
- package/dist/knowledge/progress-puzzle.d.ts +2 -2
- package/dist/knowledge/progress-puzzle.js +1 -1
- package/dist/knowledge/progress-risk.d.ts +4 -1
- package/dist/knowledge/progress-risk.js +1 -1
- package/dist/knowledge/progress-templates.js +1 -1
- package/dist/knowledge/proof-risk.d.ts +6 -5
- package/dist/knowledge/proof-risk.js +1 -1
- package/dist/knowledge/puzzle-projections.js +1 -1
- package/dist/knowledge/recipient-constraint.d.ts +20 -1
- package/dist/knowledge/recipient-constraint.js +1 -1
- package/dist/knowledge/registrar-risk.d.ts +6 -5
- package/dist/knowledge/registrar-risk.js +1 -1
- package/dist/knowledge/repository-risk.d.ts +7 -6
- package/dist/knowledge/repository-risk.js +1 -1
- package/dist/knowledge/resource-risk.d.ts +6 -5
- package/dist/knowledge/resource-risk.js +1 -1
- package/dist/knowledge/reward-ledger.d.ts +1 -1
- package/dist/knowledge/reward-ledger.js +1 -1
- package/dist/knowledge/reward-puzzle.d.ts +2 -2
- package/dist/knowledge/reward-puzzle.js +1 -1
- package/dist/knowledge/reward-risk.d.ts +4 -1
- package/dist/knowledge/reward-risk.js +1 -1
- package/dist/knowledge/rule-node-analyzers.spec.js +1 -1
- package/dist/knowledge/rule-outcome.js +1 -1
- package/dist/knowledge/scenario-modes.d.ts +2 -2
- package/dist/knowledge/scenario-modes.js +1 -1
- package/dist/knowledge/scenario-topology.js +1 -1
- package/dist/knowledge/service-allocator-audit-node.js +1 -1
- package/dist/knowledge/service-ledger.js +1 -1
- package/dist/knowledge/service-puzzle.d.ts +2 -2
- package/dist/knowledge/service-puzzle.js +1 -1
- package/dist/knowledge/service-risk-node.js +1 -1
- package/dist/knowledge/service-risk.d.ts +4 -1
- package/dist/knowledge/service-risk.js +1 -1
- package/dist/knowledge/service-templates.js +1 -1
- package/dist/knowledge/strategy-manuals.d.ts +1 -1
- package/dist/knowledge/strategy-manuals.js +1 -1
- package/dist/knowledge/template-loader.d.ts +84 -0
- package/dist/knowledge/template-loader.js +1 -0
- package/dist/knowledge/template-loader.spec.d.ts +1 -0
- package/dist/knowledge/template-loader.spec.js +1 -0
- package/dist/knowledge/template-registry.js +1 -1
- package/dist/knowledge/template-scanner.d.ts +17 -0
- package/dist/knowledge/template-scanner.js +1 -0
- package/dist/knowledge/template-scanner.spec.d.ts +1 -0
- package/dist/knowledge/template-scanner.spec.js +1 -0
- package/dist/knowledge/tools-reference.js +1 -1
- package/dist/knowledge/treasury-ledger.d.ts +1 -1
- package/dist/knowledge/treasury-ledger.js +1 -1
- package/dist/knowledge/treasury-puzzle.d.ts +3 -3
- package/dist/knowledge/treasury-puzzle.js +1 -1
- package/dist/knowledge/treasury-risk.d.ts +4 -1
- package/dist/knowledge/treasury-risk.js +1 -1
- package/dist/knowledge/treasury-templates.js +1 -1
- package/dist/knowledge/util-risk.d.ts +6 -5
- package/dist/knowledge/util-risk.js +1 -1
- package/dist/knowledge/workflow-guidance.d.ts +4 -0
- package/dist/knowledge/workflow-guidance.js +1 -1
- package/dist/knowledge/workspace-lists.js +1 -1
- package/dist/monitor/MonitorLoop.js +1 -1
- package/dist/participation/arbitrator-interest.js +1 -1
- package/dist/participation/radar-core.js +1 -1
- package/dist/persona/analyzer.js +1 -1
- package/dist/persona/index.js +1 -1
- package/dist/persona/model.js +1 -1
- package/dist/persona/persona-audit.spec.d.ts +1 -0
- package/dist/persona/persona-audit.spec.js +1 -0
- package/dist/persona/types.d.ts +2 -0
- package/dist/playbooks/service-build/business-puzzle.js +1 -1
- package/dist/playbooks/service-build/facet-money.d.ts +11 -0
- package/dist/playbooks/service-build/facet-money.js +1 -1
- package/dist/playbooks/service-build/machine-panorama.d.ts +17 -0
- package/dist/playbooks/service-build/machine-panorama.js +1 -1
- package/dist/playbooks/service-build/merchant-guide.d.ts +2 -2
- package/dist/playbooks/service-build/migration-planner.d.ts +43 -0
- package/dist/playbooks/service-build/migration-planner.js +1 -0
- package/dist/playbooks/service-build/object-panorama.d.ts +42 -1
- package/dist/playbooks/service-build/object-panorama.js +1 -1
- package/dist/playbooks/service-build/participation-radar.js +1 -1
- package/dist/playbooks/service-build/pipeline-actions.d.ts +1 -1
- package/dist/playbooks/service-build/reverse-mapping.d.ts +1 -0
- package/dist/playbooks/service-build/reverse-mapping.js +1 -1
- package/dist/playbooks/service-build/risk-aggregator.d.ts +2 -1
- package/dist/playbooks/service-build/risk-aggregator.js +1 -1
- package/dist/playbooks/service-build/semantic-graph.js +1 -1
- package/dist/playbooks/service-build/service-panorama.d.ts +53 -1
- package/dist/playbooks/service-build/service-panorama.js +1 -1
- package/dist/playbooks/service-build/topology-evaluation.spec.js +1 -1
- package/dist/playbooks/service-build/topology-query.js +1 -1
- package/dist/playbooks/service-build/workflow-design-assessment.d.ts +2 -2
- package/dist/playbooks/service-build/workflow-design-assessment.js +1 -1
- package/dist/relationship/registry.js +1 -1
- package/dist/review/machine.js +1 -1
- package/dist/review/order.js +1 -1
- package/dist/review/service.js +1 -1
- package/dist/review/types.d.ts +7 -0
- package/dist/safety/confirm-gate.js +1 -1
- package/dist/schema/benchmark-migration/index.d.ts +207 -0
- package/dist/schema/benchmark-migration/index.js +1 -0
- package/dist/schema/call/allocation.d.ts +1 -1
- package/dist/schema/call/allocation.js +1 -1
- package/dist/schema/call/arbitration.d.ts +1 -1
- package/dist/schema/call/arbitration.js +1 -1
- package/dist/schema/call/base.d.ts +5 -5
- package/dist/schema/call/base.js +1 -1
- package/dist/schema/call/contact.d.ts +1 -1
- package/dist/schema/call/demand.d.ts +1 -1
- package/dist/schema/call/guard.d.ts +3 -3
- package/dist/schema/call/machine.d.ts +5 -5
- package/dist/schema/call/order.d.ts +3 -3
- package/dist/schema/call/payment.js +1 -1
- package/dist/schema/call/permission-handler.d.ts +1 -1
- package/dist/schema/call/permission-handler.js +1 -1
- package/dist/schema/call/permission.d.ts +16 -16
- package/dist/schema/call/permission.js +1 -1
- package/dist/schema/call/personal.d.ts +8 -8
- package/dist/schema/call/personal.js +1 -1
- package/dist/schema/call/progress.d.ts +3 -3
- package/dist/schema/call/repository.d.ts +11 -11
- package/dist/schema/call/repository.js +1 -1
- package/dist/schema/call/reward.d.ts +1 -1
- package/dist/schema/call/semantic.js +1 -1
- package/dist/schema/call/service.d.ts +7 -7
- package/dist/schema/call/service.js +1 -1
- package/dist/schema/call/treasury.d.ts +1 -1
- package/dist/schema/common/index.d.ts +6 -6
- package/dist/schema/common/index.js +1 -1
- package/dist/schema/config/index.d.ts +50 -1
- package/dist/schema/config/index.js +1 -1
- package/dist/schema/evaluation/index.d.ts +27 -11
- package/dist/schema/evaluation/index.js +1 -1
- package/dist/schema/goal/index.d.ts +5 -5
- package/dist/schema/goal/planning.d.ts +15 -15
- package/dist/schema/goal/planning.js +1 -1
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -1
- package/dist/schema/interaction/index.d.ts +1 -1
- package/dist/schema/local/index.js +1 -1
- package/dist/schema/messenger/index.d.ts +26 -26
- package/dist/schema/operations.d.ts +33 -33
- package/dist/schema/operations.js +1 -1
- package/dist/schema/persona/index.d.ts +4708 -0
- package/dist/schema/persona/index.js +1 -1
- package/dist/schema/query/bi.d.ts +232 -25
- package/dist/schema/query/bi.js +1 -1
- package/dist/schema/query/index.d.ts +35 -35
- package/dist/schema/query/index.js +1 -1
- package/dist/schema/schema-version.js +1 -1
- package/dist/schema/workflow/index.d.ts +1 -1
- package/dist/schema/workspace/index.d.ts +53 -0
- package/dist/schema/workspace/index.js +1 -1
- package/dist/schema-query-impl/index.d.ts +9 -0
- package/dist/schema-query-impl/index.js +1 -1
- package/dist/schemas/benchmark_migration_operation.output.json +793 -0
- package/dist/schemas/benchmark_migration_operation.schema.json +83 -0
- package/dist/schemas/bridge_operation.schema.json +5 -5
- package/dist/schemas/config_operation.output.json +252 -0
- package/dist/schemas/config_operation.schema.json +21 -1
- package/dist/schemas/evaluation_operation.output.json +22 -10
- package/dist/schemas/goal_operation.schema.json +8 -8
- package/dist/schemas/guard2file.schema.json +1 -1
- package/dist/schemas/index.json +7 -1
- package/dist/schemas/machineNode2file.schema.json +1 -1
- package/dist/schemas/messenger_operation.schema.json +24 -12
- package/dist/schemas/onchain_events.output.json +1 -1
- package/dist/schemas/onchain_operations.output.json +4 -2
- package/dist/schemas/onchain_operations.schema.json +189 -139
- package/dist/schemas/onchain_operations_allocation.schema.json +13 -11
- package/dist/schemas/onchain_operations_arbitration.schema.json +10 -8
- package/dist/schemas/onchain_operations_contact.schema.json +7 -5
- package/dist/schemas/onchain_operations_demand.schema.json +7 -5
- package/dist/schemas/onchain_operations_gen_passport.schema.json +5 -3
- package/dist/schemas/onchain_operations_gen_proof.schema.json +1 -1
- package/dist/schemas/onchain_operations_guard.schema.json +5 -3
- package/dist/schemas/onchain_operations_machine.schema.json +22 -18
- package/dist/schemas/onchain_operations_order.schema.json +11 -7
- package/dist/schemas/onchain_operations_payment.schema.json +3 -3
- package/dist/schemas/onchain_operations_permission.schema.json +19 -11
- package/dist/schemas/onchain_operations_personal.schema.json +16 -10
- package/dist/schemas/onchain_operations_progress.schema.json +11 -7
- package/dist/schemas/onchain_operations_proof.schema.json +5 -3
- package/dist/schemas/onchain_operations_repository.schema.json +12 -8
- package/dist/schemas/onchain_operations_reward.schema.json +11 -9
- package/dist/schemas/onchain_operations_service.schema.json +28 -22
- package/dist/schemas/onchain_operations_treasury.schema.json +11 -9
- package/dist/schemas/onchain_table_data.output.json +27 -17
- package/dist/schemas/persona_operation.output.json +15875 -1
- package/dist/schemas/persona_operation.schema.json +3056 -478
- package/dist/schemas/query_toolkit.output.json +343 -63
- package/dist/schemas/query_toolkit.schema.json +1 -1
- package/dist/schemas/workflow_operation.schema.json +4 -2
- package/dist/schemas/workspace_operation.output.json +181 -1
- package/dist/schemas/workspace_operation.schema.json +61 -2
- package/dist/strategy/scorecard.js +1 -1
- package/dist/tools/handlers/benchmark-migration.d.ts +2 -0
- package/dist/tools/handlers/benchmark-migration.js +1 -0
- package/dist/tools/handlers/config.js +1 -1
- package/dist/tools/handlers/industry-pack.js +1 -1
- package/dist/tools/handlers/onchain.js +1 -1
- package/dist/tools/handlers/query.js +1 -1
- package/dist/tools/handlers/schema-query.js +1 -1
- package/dist/tools/handlers/workspace.js +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/move-fn-index.gen.d.ts +3 -0
- package/dist/tools/move-fn-index.gen.js +1 -0
- package/dist/tools/registry/business.js +1 -1
- package/dist/tools/registry/config.js +1 -1
- package/dist/tools/registry/evaluation.js +1 -1
- package/dist/tools/registry/onchain.js +1 -1
- package/dist/tools/sanitize-output.d.ts +3 -0
- package/dist/tools/sanitize-output.js +1 -0
- package/dist/tools/sanitize-output.spec.d.ts +1 -0
- package/dist/tools/sanitize-output.spec.js +1 -0
- package/package.json +9 -4
- package/dist/knowledge/baselines/evaluation-baselines.json +0 -79
|
@@ -1 +1 @@
|
|
|
1
|
-
import{COMMERCIAL_ROLES}from'../../role/types.js';import{resolveInterests,ROLE_INTERESTS}from'../../evaluation/game-strategy.js';import{evaluateNodeGame}from'../../evaluation/node-game.js';import{evaluateArbGame}from'../../evaluation/arbitration-game.js';import{consequenceOf,recommendedCallForExecutionPath}from'../../participation/radar-core.js';import{buildViewport}from'./viewport.js';import{buildControlIndex,pathConfidence,runAnalyzers}from'./analyze.js';import{orderCompletionInGraph}from'./expand.js';const VIEWER_OF={'customer':'buyer','prospect':'buyer','demander':'demander','merchant':'merchant','collaborator':'collaborator','supplier':'supplier','arbitrator':'arbitrator','neutral':'neutral','system':'system'},COMMERCIAL_ROLE_SET=new Set(COMMERCIAL_ROLES);export function toCommercialRole(a){if(a==='buyer')return'customer';return COMMERCIAL_ROLE_SET['has'](a)?a:'neutral';}export function viewerRoleOf(a){return VIEWER_OF[a];}function root(a){const b=a?.['raw'],c=b?.['data']??b;return c&&typeof c==='object'?c:undefined;}function str(a){return typeof a==='string'&&a!=='0x0'?a:undefined;}function objNode(a,b){const c=a['graph']['nodes']['get'](b['toLowerCase']());return c&&a['visibleNodes']['has'](c['id'])&&c['kind']==='object'&&c['raw']?c:undefined;}function visible(a,b){return a['visibleEdges']['filter'](c=>c['schema']===b);}function outEdges(a,b,c){const d=b['toLowerCase']();return a['visibleEdges']['filter'](f=>f['schema']===c&&f['from']===d);}function incEdges(a,b,c){const d=b['toLowerCase']();return a['visibleEdges']['filter'](f=>f['schema']===c&&f['to']===d);}function wfMachineOf(a){const b=a['indexOf']('::node::');return b>=0x0?a['slice'](0x0,b):'';}function wfNodeName(a){const b=a['indexOf']('::node::');return b>=0x0?a['slice'](b+'::node::'['length']):a;}function heldPermissionIndices(a,c){const d=new Map();for(const f of outEdges(a,c,'eoa.permission')){const g=new Set();d['set'](f['to'],g);for(const h of outEdges(a,f['to'],'permission.entity')){for(const i of Array['isArray'](h['payload']?.['permIndices'])?h['payload']['permIndices']:[]){const j=Number(i);if(Number['isInteger'](j))g['add'](j);}}}return d;}const MAX_STAKES=0x10;function orderStake(a,b,c,e){const f=objNode(a,b),g=root(f)??{},h=orderCompletionInGraph(a['graph'],b);return{'object':b['toLowerCase'](),'object_type':f?.['objectType']??'Order','positions':c,...str(g['amount'])?{'amount':String(g['amount'])}:{},...f?.['coinType']?{'coin_type':f['coinType']}:{},...h['status']!=='unknown'||f?{'state':h['status']}:{},'evidence':e};}function arbState(a,b){return str(root(objNode(a,b))?.['status']);}function collectStakes(a,b,c,d){const f=new Map(),g=(j,k,l,m)=>{const n=j['toLowerCase'](),o=f['get'](n);if(o){if(!o['positions']['includes'](k))o['positions']['push'](k);for(const p of l)if(!o['evidence']['includes'](p))o['evidence']['push'](p);return;}if(f['size']>=MAX_STAKES)return;f['set'](n,m([k],l));},h=new Set();for(const j of outEdges(a,b,'eoa.order'))h['add'](j['to']);for(const k of incEdges(a,b,'order.builder'))h['add'](k['from']);for(const l of h){g(l,'buyer',['eoa.order','order.builder'],(m,n)=>orderStake(a,l,m,n));}const i=new Set(d['keys']());for(const m of outEdges(a,b,'eoa.permission'))i['add'](m['to']);for(const [n,o]of c['objectsByEoa']){if(n!==b)continue;for(const p of o){const q=a['graph']['nodes']['get'](p);q?.['objectType']==='Demand'?g(p,'demand_owner',['eoa.permission','demand.permission'],(r,s)=>{const t=outEdges(a,p,'demand.presenter')['length'];return{'object':p['toLowerCase'](),'object_type':'Demand','positions':r,'state':t+'\x20presenter(s)','evidence':s};}):g(p,'controller',['eoa.permission','permission.core_binding'],(r,s)=>({'object':p['toLowerCase'](),'object_type':q?.['objectType']??'object','positions':r,'evidence':s}));}}for(const r of visible(a,'demand.permission')){if(!i['has'](r['to']))continue;g(r['from'],'demand_owner',['demand.permission'],(s,t)=>{const u=outEdges(a,r['from'],'demand.presenter')['length'];return{'object':r['from']['toLowerCase'](),'object_type':'Demand','positions':s,'state':u+'\x20presenter(s)','evidence':t};});}for(const [s,t]of c['objectsByEoa']){if(s!==b)continue;for(const u of t){if(a['graph']['nodes']['get'](u)?.['objectType']!=='Service')continue;for(const w of outEdges(a,u,'service.order')){g(w['to'],'seller',['service.order'],(x,y)=>orderStake(a,w['to'],x,y));}}}for(const x of incEdges(a,b,'demand.presenter')){g(x['from'],'presenter',['demand.presenter'],(y,z)=>({'object':x['from']['toLowerCase'](),'object_type':a['graph']['nodes']['get'](x['from'])?.['objectType']??'Demand','positions':y,'evidence':z}));}for(const y of incEdges(a,b,'arb.voter')){g(y['from'],'voter',['arb.voter'],(z,A)=>{const B=arbState(a,y['from']);return{'object':y['from']['toLowerCase'](),'object_type':'Arb','positions':z,...B?{'state':B}:{},'evidence':A};});}for(const [z,A]of c['objectsByEoa']){if(z!==b)continue;for(const B of A){if(a['graph']['nodes']['get'](B)?.['objectType']!=='Arbitration')continue;for(const C of incEdges(a,B,'arb.arbitration_service')){g(C['from'],'arbitration_owner',['arb.arbitration_service'],(D,E)=>{const F=arbState(a,C['from']);return{'object':C['from']['toLowerCase'](),'object_type':'Arb','positions':D,...F?{'state':F}:{},'evidence':E};});}}}for(const [D,E]of f){if(a['graph']['nodes']['get'](D)?.['objectType']!=='Order')continue;if(outEdges(a,D,'order.dispute')['length']>0x0&&!E['positions']['includes']('disputant')){E['positions']['push']('disputant');if(!E['evidence']['includes']('order.dispute'))E['evidence']['push']('order.dispute');}}return[...f['values']()];}const MAX_ACTION_GROUPS=0x8;function forwardsAt(a,b,c){const d=b['toLowerCase']()+'::node::',f=[];for(const g of a['visibleEdges']){if(g['schema']!=='wf.transition'||!g['from']['startsWith'](d))continue;if(wfNodeName(g['from'])!==c)continue;f['push']({'edge':g,'name':String(g['payload']?.['forward']??g['payload']?.['prevNode']+'→'+g['payload']?.['node']),'toNode':String(g['payload']?.['node']??wfNodeName(g['to'])),'permissionIndex':typeof g['payload']?.['permissionIndex']==='number'?g['payload']['permissionIndex']:null,'namedOperator':typeof g['payload']?.['namedOperator']==='string'?g['payload']['namedOperator']:null,'guard':str(g['payload']?.['guard']),'weight':typeof g['payload']?.['weight']==='number'?g['payload']['weight']:undefined,'threshold':typeof g['payload']?.['threshold']==='number'?g['payload']['threshold']:undefined});}return f;}function executionPathOf(a,b,c){if(a['permissionIndex']!=null)return c['has'](a['permissionIndex'])?'permission':'not_available';if(a['namedOperator']==='')return b?'order_holder':'not_available';return'not_available';}function allocationSummaryOf(a,b,c,e){const f=outEdges(a,b,'order.allocation')[0x0]?.['to'];if(!f)return undefined;const g=root(objNode(a,f)),h=Array['isArray'](g?.['allocators'])?g['allocators']:[];if(h['length']===0x0)return undefined;let i=0x0,j=0x0,k=0x0,l=0x0;const m=o=>{if(typeof o==='string')return o['startsWith']('0x')||o['startsWith']('00')?o['toLowerCase']():undefined;if(o&&typeof o==='object'){const p=o;if('Entity'in p)return typeof p['Entity']==='string'?p['Entity']['toLowerCase']():undefined;}return undefined;},n=o=>(o&&typeof o==='object'&&'GuardIdentifier'in o)===!![];for(const o of h){const p=o??{};for(const q of Array['isArray'](p['sharing'])?p['sharing']:[]){const r=q??{};i++;const t=m(r['who']);if(t===c['toLowerCase']())k++;else{if(e&&t===e['toLowerCase']())l++;else{if(r['who']==='Signer')l++;else{if(n(r['who']))j++;}}}}}if(i===0x0)return undefined;return{'recipient_slots':i,'guard_gated_slots':j,'direct_to_me_slots':k,'to_payer_slots':l};}function actionGroupFor(a,b,c,e,g,h,i){const j=objNode(a,g),k=root(j)??{},l=str(k['progress']),m=str(k['machine'])??wfMachineOf(l??''),n=l?root(objNode(a,l)):undefined,o=str(n?.['current'])??'';if(!m||!o||!l)return undefined;const p=forwardsAt(a,m,o);if(p['length']===0x0)return undefined;const q=outEdges(a,g,'order.service')[0x0]?.['to'],r=q?root(objNode(a,q)):undefined,s=outEdges(a,g,'order.builder')[0x0]?.['to'],t=[],u=[],w=new Map(),x=[];for(const A of p){const B=executionPathOf(A,h,i);if(B==='not_available'){const D=A['permissionIndex']!=null?'requires\x20permission\x20index\x20'+A['permissionIndex']+'\x20(not\x20held\x20by\x20the\x20observer\x20in\x20this\x20view)':A['namedOperator']!=null&&A['namedOperator']!==''?'named\x20operator\x20\x27'+A['namedOperator']+'\x27\x20resolves\x20off-chain\x20(LocalMark)\x20—\x20not\x20decidable\x20from\x20graph\x20evidence':'unbound\x20forward\x20—\x20only\x20a\x20guard\x20or\x20the\x20payer\x27s\x20transaction\x20can\x20advance\x20it';u['push']({'forward':A['name'],'reason':D});const E=A['permissionIndex']!=null?'permission\x20index\x20'+A['permissionIndex']:A['namedOperator']!=null&&A['namedOperator']!==''?'named\x20operator\x20\x27'+A['namedOperator']+'\x27':'guard/payer-direct\x20only',F=w['get'](E)??[];F['push'](A['name']),w['set'](E,F);continue;}const C=recommendedCallForExecutionPath(B,A['guard']!=null);t['push']({'name':A['name'],'to_node':A['toNode'],'execution_path':B,...A['guard']?{'guard':A['guard']}:{},'consequence':consequenceOf(A['toNode'],undefined),...A['weight']!==undefined?{'weight':A['weight']}:{}});if(C)x['push']({'forward':A['name'],'call':C});}const y=Math['max'](0x1,...p['map'](G=>G['threshold']??0x1)),z=evaluateNodeGame({'current_node':o,'perspective':c,...e?.['risk_appetite']?{'appetite':e['risk_appetite']}:{},...y>0x1?{'threshold':y}:{},'allocation':allocationSummaryOf(a,g,b,s),...e?.['requirements']?{'requirements':e['requirements']}:{},...str(k['amount'])?{'order_amount':String(k['amount'])}:{},...r&&str(r['compensation_fund'])?{'compensation_fund':String(r['compensation_fund'])}:{},'operable':t,'waiting_on':[...w['entries']()]['map'](([G,H])=>({'role':G,'forwards':H}))});return{'order':g['toLowerCase'](),'machine':m['toLowerCase'](),'current_node':o,'advice':z,'recommended_calls':x,'blocked_forwards':u};}function collectActions(a,c,d,e,f,g){const h=new Set();for(const j of g['values']())for(const k of j)h['add'](k);const i=[];for(const l of f){if(i['length']>=MAX_ACTION_GROUPS)break;if(a['graph']['nodes']['get'](l['object'])?.['objectType']!=='Order')continue;const m=l['positions']['includes']('buyer'),n=actionGroupFor(a,c,d,e,l['object'],m,h);n&&(n['advice']['actions']['length']>0x0||n['blocked_forwards']['length']>0x0)&&i['push'](n);}return i;}function arbPerspectiveOf(a,b,c){if(c['positions']['includes']('voter')||c['positions']['includes']('arbitration_owner'))return'arbitrator';if(c['positions']['includes']('buyer')||c['positions']['includes']('disputant'))return'customer';if(c['positions']['includes']('seller'))return'merchant';return undefined;}function collectArbActions(a,b,c,d){const e=[];for(const f of d){if(a['graph']['nodes']['get'](f['object'])?.['objectType']!=='Arb')continue;const g=arbPerspectiveOf(a,b,f),h=arbState(a,f['object']);if(!g||!h)continue;e['push'](evaluateArbGame(h,g,{...c?.['risk_appetite']?{'risk_appetite':c['risk_appetite']}:{},...c?.['requirements']?{'requirements':c['requirements']}:{}}));}return e;}const SEVERITY_RANK={'info':0x0,'low':0x1,'medium':0x2,'high':0x3,'critical':0x4},MAX_COUNTERPARTIES=0x8;function collectCounterparties(a,b,c,d,e,f){const g=resolveInterests(c,d),h=[],i=(j,k,l)=>{if(h['length']>=MAX_COUNTERPARTIES)return;const m=ROLE_INTERESTS[k],n=[...g['prefer']['filter'](r=>m['avoid']['includes'](r)),...g['avoid']['filter'](r=>m['prefer']['includes'](r))],o=g['prefer']['filter'](r=>m['prefer']['includes'](r)),p=n['length']>0x0?'conflict':o['length']>0x0?'aligned':'neutral',q=p==='conflict'?'Structural\x20conflict\x20of\x20interest:\x20you\x20prefer\x20'+(g['prefer']['filter'](r=>m['avoid']['includes'](r))['join'](',\x20')||'(none)')+',\x20which\x20'+k+'\x20treats\x20as\x20a\x20risk;\x20they\x20pursue\x20'+(m['prefer']['join'](',\x20')||'(none)')+'.':p==='aligned'?'Aligned\x20interests:\x20both\x20sides\x20prefer\x20'+o['join'](',\x20')+'.':'No\x20direct\x20interest\x20overlap\x20('+k+'\x20prefers\x20'+(m['prefer']['join'](',\x20')||'none')+'\x20and\x20avoids\x20'+(m['avoid']['join'](',\x20')||'none')+').';h['push']({'object':j['toLowerCase'](),'counter_role':k,'who':l,'their_prefer':m['prefer'],'their_avoid':m['avoid'],'alignment':p,'note':q});};for(const j of e){if(a['graph']['nodes']['get'](j['object'])?.['objectType']!=='Order')continue;const k=outEdges(a,j['object'],'order.service')[0x0]?.['to'],l=k?[...f['controllers']['get'](k['toLowerCase']())??[]]:[];i(j['object'],'merchant',l);const m=outEdges(a,j['object'],'order.builder')[0x0]?.['to'];if(m&&m!==b['toLowerCase']())i(j['object'],'customer',[m]);if(outEdges(a,j['object'],'order.dispute')['length']>0x0)i(j['object'],'arbitrator',[]);}return h;}const MAX_RISK_REMINDERS=0xa;function collectRiskReminders(a,b){try{return runAnalyzers(a,{'kinds':['risk']})['filter'](c=>c['roles']['includes'](b)||c['roles']['includes']('neutral'))['sort']((c,d)=>SEVERITY_RANK[d['severity']]-SEVERITY_RANK[c['severity']])['slice'](0x0,MAX_RISK_REMINDERS);}catch{return[];}}export function buildRoleInterest(a,b,c,d){const e=b['toLowerCase'](),f=VIEWER_OF[c],g=buildViewport(a,e,f),h=buildControlIndex(g),i=heldPermissionIndices(g,e),j=collectStakes(g,e,h,i),k=collectActions(g,e,c,d,j,i),l=collectArbActions(g,e,d,j),m=collectCounterparties(g,e,c,d,j,h),n=collectRiskReminders(g,f),o=k['find'](y=>y['advice']['actions']['length']>0x0)?.['advice']['actions'][0x0],p=m['find'](y=>y['alignment']==='conflict'),q='Viewing\x20'+e+'\x20as\x20'+c+':\x20'+(j['length']+'\x20stake(s)\x20in\x20flight\x20('+j['map'](y=>y['object_type']+':'+y['positions']['join']('/'))['slice'](0x0,0x4)['join'](',\x20')+(j['length']>0x4?'\x20etc.':'')+');\x20')+(o?'the\x20best\x20currently\x20operable\x20action\x20is\x20\x27'+o['forward']+'\x27\x20on\x20order\x20'+(k['find'](y=>y['advice']['actions'][0x0]===o)?.['order']??'')+'\x20('+o['payoff_note']+');\x20':k['length']>0x0?'orders\x20in\x20flight\x20but\x20no\x20action\x20operable\x20from\x20this\x20view\x20(waiting\x20on\x20others\x20or\x20off-chain\x20resolution);\x20':'no\x20operable\x20in-flight\x20orders;\x20')+(l['length']>0x0?l['length']+'\x20arbitration\x20case\x20action\x20suggestion(s);\x20':'')+(p?'largest\x20structural\x20counterparty\x20tension:\x20'+p['counter_role']+'\x20('+p['note']+')':'no\x20notable\x20counterparty\x20tension')+(n['length']>0x0?'\x20'+n['length']+'\x20role-relevant\x20risk\x20reminder(s).':''),r={'role':c,'observer':e,...d&&(d['risk_appetite']||d['requirements']?.['length'])?{'drive':d}:{},'stakes':j,'actions':k,'arb_actions':l,'counterparties':m,'risk_finding_ids':n['map'](y=>y['id']),'summary':q},s=g['visibleEdges']['filter'](y=>['eoa.order','service.order','demand.presenter','arb.voter','order.dispute']['includes'](y['schema'])),{confidence:t,window:u}=pathConfidence(g,s),w=n['length']>0x0&&SEVERITY_RANK[n[0x0]['severity']]>=SEVERITY_RANK['medium']?n[0x0]['severity']:'info',x={'id':'IR:'+c+':'+e,'kind':'game','severity':w,'title':'Role\x20interest\x20view\x20('+c+'):\x20'+j['length']+'\x20stake(s)\x20in\x20flight'+(o?',\x20best\x20action\x20\x27'+o['forward']+'\x27':''),'path':[e,...j['map'](y=>y['object'])],'confidence':t,...u?{'window':u}:{},'roles':[f],'detail':q,'suggestion':o?'Execute\x20in\x20advice\x20order\x20(\x27'+o['forward']+'\x27\x20'+(o['guard']?'requires\x20Guard\x20passport\x20verification\x20first\x20and\x20':'')+'goes\x20through\x20the\x20tool\x20routing\x20in\x20recommended_calls);\x20see\x20the\x20payload\x20for\x20counterparty\x20tension\x20and\x20risk\x20reminders.':'When\x20no\x20action\x20is\x20operable:\x20watch\x20blocked_forwards\x20waiting\x20conditions\x20and\x20counterparty\x20tension\x20changes,\x20or\x20re-project\x20with\x20a\x20different\x20role/context_account.','interest':r};return{'finding':x,'view':r};}
|
|
1
|
+
import{COMMERCIAL_ROLES}from'../../role/types.js';import{resolveInterests,interestsOf}from'../../evaluation/game-strategy.js';import{evaluateNodeGame}from'../../evaluation/node-game.js';import{evaluateArbGame}from'../../evaluation/arbitration-game.js';import{consequenceOf,recommendedCallForExecutionPath}from'../../participation/radar-core.js';import{buildViewport}from'./viewport.js';import{buildControlIndex,pathConfidence,runAnalyzers}from'./analyze.js';import{orderCompletionInGraph}from'./expand.js';const VIEWER_OF={'customer':'buyer','prospect':'buyer','demander':'demander','merchant':'merchant','collaborator':'collaborator','supplier':'supplier','arbitrator':'arbitrator','neutral':'neutral','system':'system'},COMMERCIAL_ROLE_SET=new Set(COMMERCIAL_ROLES);export function toCommercialRole(a){if(a==='buyer')return'customer';return COMMERCIAL_ROLE_SET['has'](a)?a:'neutral';}export function viewerRoleOf(a){return VIEWER_OF[a];}function root(a){const b=a?.['raw'],c=b?.['data']??b;return c&&typeof c==='object'?c:undefined;}function str(a){return typeof a==='string'&&a!=='0x0'?a:undefined;}function objNode(a,b){const c=a['graph']['nodes']['get'](b['toLowerCase']());return c&&a['visibleNodes']['has'](c['id'])&&c['kind']==='object'&&c['raw']?c:undefined;}function visible(a,b){return a['visibleEdges']['filter'](c=>c['schema']===b);}function outEdges(a,b,c){const d=b['toLowerCase']();return a['visibleEdges']['filter'](f=>f['schema']===c&&f['from']===d);}function incEdges(a,b,c){const d=b['toLowerCase']();return a['visibleEdges']['filter'](f=>f['schema']===c&&f['to']===d);}function wfMachineOf(a){const b=a['indexOf']('::node::');return b>=0x0?a['slice'](0x0,b):'';}function wfNodeName(a){const b=a['indexOf']('::node::');return b>=0x0?a['slice'](b+'::node::'['length']):a;}function heldPermissionIndices(a,c){const d=new Map();for(const f of outEdges(a,c,'eoa.permission')){const g=new Set();d['set'](f['to'],g);for(const h of outEdges(a,f['to'],'permission.entity')){for(const i of Array['isArray'](h['payload']?.['permIndices'])?h['payload']['permIndices']:[]){const j=Number(i);if(Number['isInteger'](j))g['add'](j);}}}return d;}const MAX_STAKES=0x10;function orderStake(a,b,c,e){const f=objNode(a,b),g=root(f)??{},h=orderCompletionInGraph(a['graph'],b);return{'object':b['toLowerCase'](),'object_type':f?.['objectType']??'Order','positions':c,...str(g['amount'])?{'amount':String(g['amount'])}:{},...f?.['coinType']?{'coin_type':f['coinType']}:{},...h['status']!=='unknown'||f?{'state':h['status']}:{},'evidence':e};}function arbState(a,b){return str(root(objNode(a,b))?.['status']);}function collectStakes(a,b,c,d){const f=new Map(),g=(j,k,l,m)=>{const n=j['toLowerCase'](),o=f['get'](n);if(o){if(!o['positions']['includes'](k))o['positions']['push'](k);for(const p of l)if(!o['evidence']['includes'](p))o['evidence']['push'](p);return;}if(f['size']>=MAX_STAKES)return;f['set'](n,m([k],l));},h=new Set();for(const j of outEdges(a,b,'eoa.order'))h['add'](j['to']);for(const k of incEdges(a,b,'order.builder'))h['add'](k['from']);for(const l of h){g(l,'buyer',['eoa.order','order.builder'],(m,n)=>orderStake(a,l,m,n));}const i=new Set(d['keys']());for(const m of outEdges(a,b,'eoa.permission'))i['add'](m['to']);for(const [n,o]of c['objectsByEoa']){if(n!==b)continue;for(const p of o){const q=a['graph']['nodes']['get'](p);q?.['objectType']==='Demand'?g(p,'demand_owner',['eoa.permission','demand.permission'],(r,s)=>{const t=outEdges(a,p,'demand.presenter')['length'];return{'object':p['toLowerCase'](),'object_type':'Demand','positions':r,'state':t+'\x20presenter(s)','evidence':s};}):g(p,'controller',['eoa.permission','permission.core_binding'],(r,s)=>({'object':p['toLowerCase'](),'object_type':q?.['objectType']??'object','positions':r,'evidence':s}));}}for(const r of visible(a,'demand.permission')){if(!i['has'](r['to']))continue;g(r['from'],'demand_owner',['demand.permission'],(s,t)=>{const u=outEdges(a,r['from'],'demand.presenter')['length'];return{'object':r['from']['toLowerCase'](),'object_type':'Demand','positions':s,'state':u+'\x20presenter(s)','evidence':t};});}for(const [s,t]of c['objectsByEoa']){if(s!==b)continue;for(const u of t){if(a['graph']['nodes']['get'](u)?.['objectType']!=='Service')continue;for(const w of outEdges(a,u,'service.order')){g(w['to'],'seller',['service.order'],(x,y)=>orderStake(a,w['to'],x,y));}}}for(const x of incEdges(a,b,'demand.presenter')){g(x['from'],'presenter',['demand.presenter'],(y,z)=>({'object':x['from']['toLowerCase'](),'object_type':a['graph']['nodes']['get'](x['from'])?.['objectType']??'Demand','positions':y,'evidence':z}));}for(const y of incEdges(a,b,'arb.voter')){g(y['from'],'voter',['arb.voter'],(z,A)=>{const B=arbState(a,y['from']);return{'object':y['from']['toLowerCase'](),'object_type':'Arb','positions':z,...B?{'state':B}:{},'evidence':A};});}for(const [z,A]of c['objectsByEoa']){if(z!==b)continue;for(const B of A){if(a['graph']['nodes']['get'](B)?.['objectType']!=='Arbitration')continue;for(const C of incEdges(a,B,'arb.arbitration_service')){g(C['from'],'arbitration_owner',['arb.arbitration_service'],(D,E)=>{const F=arbState(a,C['from']);return{'object':C['from']['toLowerCase'](),'object_type':'Arb','positions':D,...F?{'state':F}:{},'evidence':E};});}}}for(const [D,E]of f){if(a['graph']['nodes']['get'](D)?.['objectType']!=='Order')continue;if(outEdges(a,D,'order.dispute')['length']>0x0&&!E['positions']['includes']('disputant')){E['positions']['push']('disputant');if(!E['evidence']['includes']('order.dispute'))E['evidence']['push']('order.dispute');}}return[...f['values']()];}const MAX_ACTION_GROUPS=0x8;function forwardsAt(a,b,c){const d=b['toLowerCase']()+'::node::',f=[];for(const g of a['visibleEdges']){if(g['schema']!=='wf.transition'||!g['from']['startsWith'](d))continue;if(wfNodeName(g['from'])!==c)continue;f['push']({'edge':g,'name':String(g['payload']?.['forward']??g['payload']?.['prevNode']+'→'+g['payload']?.['node']),'toNode':String(g['payload']?.['node']??wfNodeName(g['to'])),'permissionIndex':typeof g['payload']?.['permissionIndex']==='number'?g['payload']['permissionIndex']:null,'namedOperator':typeof g['payload']?.['namedOperator']==='string'?g['payload']['namedOperator']:null,'guard':str(g['payload']?.['guard']),'weight':typeof g['payload']?.['weight']==='number'?g['payload']['weight']:undefined,'threshold':typeof g['payload']?.['threshold']==='number'?g['payload']['threshold']:undefined});}return f;}function executionPathOf(a,b,c){if(a['permissionIndex']!=null)return c['has'](a['permissionIndex'])?'permission':'not_available';if(a['namedOperator']==='')return b?'order_holder':'not_available';return'not_available';}function allocationSummaryOf(a,b,c,e){const f=outEdges(a,b,'order.allocation')[0x0]?.['to'];if(!f)return undefined;const g=root(objNode(a,f)),h=Array['isArray'](g?.['allocators'])?g['allocators']:[];if(h['length']===0x0)return undefined;let i=0x0,j=0x0,k=0x0,l=0x0;const m=o=>{if(typeof o==='string')return o['startsWith']('0x')||o['startsWith']('00')?o['toLowerCase']():undefined;if(o&&typeof o==='object'){const p=o;if('Entity'in p)return typeof p['Entity']==='string'?p['Entity']['toLowerCase']():undefined;}return undefined;},n=o=>(o&&typeof o==='object'&&'GuardIdentifier'in o)===!![];for(const o of h){const p=o??{};for(const q of Array['isArray'](p['sharing'])?p['sharing']:[]){const r=q??{};i++;const t=m(r['who']);if(t===c['toLowerCase']())k++;else{if(e&&t===e['toLowerCase']())l++;else{if(r['who']==='Signer')l++;else{if(n(r['who']))j++;}}}}}if(i===0x0)return undefined;return{'recipient_slots':i,'guard_gated_slots':j,'direct_to_me_slots':k,'to_payer_slots':l};}function actionGroupFor(a,b,c,e,g,h,i){const j=objNode(a,g),k=root(j)??{},l=str(k['progress']),m=str(k['machine'])??wfMachineOf(l??''),n=l?root(objNode(a,l)):undefined,o=str(n?.['current'])??'';if(!m||!o||!l)return undefined;const p=forwardsAt(a,m,o);if(p['length']===0x0)return undefined;const q=outEdges(a,g,'order.service')[0x0]?.['to'],r=q?root(objNode(a,q)):undefined,s=outEdges(a,g,'order.builder')[0x0]?.['to'],t=[],u=[],w=new Map(),x=[];for(const A of p){const B=executionPathOf(A,h,i);if(B==='not_available'){const D=A['permissionIndex']!=null?'requires\x20permission\x20index\x20'+A['permissionIndex']+'\x20(not\x20held\x20by\x20the\x20observer\x20in\x20this\x20view)':A['namedOperator']!=null&&A['namedOperator']!==''?'named\x20operator\x20\x27'+A['namedOperator']+'\x27\x20resolves\x20off-chain\x20(LocalMark)\x20—\x20not\x20decidable\x20from\x20graph\x20evidence':'unbound\x20forward\x20—\x20only\x20a\x20guard\x20or\x20the\x20payer\x27s\x20transaction\x20can\x20advance\x20it';u['push']({'forward':A['name'],'reason':D});const E=A['permissionIndex']!=null?'permission\x20index\x20'+A['permissionIndex']:A['namedOperator']!=null&&A['namedOperator']!==''?'named\x20operator\x20\x27'+A['namedOperator']+'\x27':'guard/payer-direct\x20only',F=w['get'](E)??[];F['push'](A['name']),w['set'](E,F);continue;}const C=recommendedCallForExecutionPath(B,A['guard']!=null);t['push']({'name':A['name'],'to_node':A['toNode'],'execution_path':B,...A['guard']?{'guard':A['guard']}:{},'consequence':consequenceOf(A['toNode'],undefined),...A['weight']!==undefined?{'weight':A['weight']}:{}});if(C)x['push']({'forward':A['name'],'call':C});}const y=Math['max'](0x1,...p['map'](G=>G['threshold']??0x1)),z=evaluateNodeGame({'current_node':o,'perspective':c,...e?.['risk_appetite']?{'appetite':e['risk_appetite']}:{},...y>0x1?{'threshold':y}:{},'allocation':allocationSummaryOf(a,g,b,s),...e?.['requirements']?{'requirements':e['requirements']}:{},...str(k['amount'])?{'order_amount':String(k['amount'])}:{},...r&&str(r['compensation_fund'])?{'compensation_fund':String(r['compensation_fund'])}:{},'operable':t,'waiting_on':[...w['entries']()]['map'](([G,H])=>({'role':G,'forwards':H}))});return{'order':g['toLowerCase'](),'machine':m['toLowerCase'](),'current_node':o,'advice':z,'recommended_calls':x,'blocked_forwards':u};}function collectActions(a,c,d,e,f,g){const h=new Set();for(const j of g['values']())for(const k of j)h['add'](k);const i=[];for(const l of f){if(i['length']>=MAX_ACTION_GROUPS)break;if(a['graph']['nodes']['get'](l['object'])?.['objectType']!=='Order')continue;const m=l['positions']['includes']('buyer'),n=actionGroupFor(a,c,d,e,l['object'],m,h);n&&(n['advice']['actions']['length']>0x0||n['blocked_forwards']['length']>0x0)&&i['push'](n);}return i;}function arbPerspectiveOf(a,b,c){if(c['positions']['includes']('voter')||c['positions']['includes']('arbitration_owner'))return'arbitrator';if(c['positions']['includes']('buyer')||c['positions']['includes']('disputant'))return'customer';if(c['positions']['includes']('seller'))return'merchant';return undefined;}function collectArbActions(a,b,c,d){const e=[];for(const f of d){if(a['graph']['nodes']['get'](f['object'])?.['objectType']!=='Arb')continue;const g=arbPerspectiveOf(a,b,f),h=arbState(a,f['object']);if(!g||!h)continue;e['push'](evaluateArbGame(h,g,{...c?.['risk_appetite']?{'risk_appetite':c['risk_appetite']}:{},...c?.['requirements']?{'requirements':c['requirements']}:{}}));}return e;}const SEVERITY_RANK={'info':0x0,'low':0x1,'medium':0x2,'high':0x3,'critical':0x4},MAX_COUNTERPARTIES=0x8;function collectCounterparties(a,b,c,d,e,f){const g=resolveInterests(c,d),h=[],i=(j,k,l)=>{if(h['length']>=MAX_COUNTERPARTIES)return;const m=interestsOf(k),n=[...g['prefer']['filter'](r=>m['avoid']['includes'](r)),...g['avoid']['filter'](r=>m['prefer']['includes'](r))],o=g['prefer']['filter'](r=>m['prefer']['includes'](r)),p=n['length']>0x0?'conflict':o['length']>0x0?'aligned':'neutral',q=p==='conflict'?'Structural\x20conflict\x20of\x20interest:\x20you\x20prefer\x20'+(g['prefer']['filter'](r=>m['avoid']['includes'](r))['join'](',\x20')||'(none)')+',\x20which\x20'+k+'\x20treats\x20as\x20a\x20risk;\x20they\x20pursue\x20'+(m['prefer']['join'](',\x20')||'(none)')+'.':p==='aligned'?'Aligned\x20interests:\x20both\x20sides\x20prefer\x20'+o['join'](',\x20')+'.':'No\x20direct\x20interest\x20overlap\x20('+k+'\x20prefers\x20'+(m['prefer']['join'](',\x20')||'none')+'\x20and\x20avoids\x20'+(m['avoid']['join'](',\x20')||'none')+').';h['push']({'object':j['toLowerCase'](),'counter_role':k,'who':l,'their_prefer':m['prefer'],'their_avoid':m['avoid'],'alignment':p,'note':q});};for(const j of e){if(a['graph']['nodes']['get'](j['object'])?.['objectType']!=='Order')continue;const k=outEdges(a,j['object'],'order.service')[0x0]?.['to'],l=k?[...f['controllers']['get'](k['toLowerCase']())??[]]:[];i(j['object'],'merchant',l);const m=outEdges(a,j['object'],'order.builder')[0x0]?.['to'];if(m&&m!==b['toLowerCase']())i(j['object'],'customer',[m]);if(outEdges(a,j['object'],'order.dispute')['length']>0x0)i(j['object'],'arbitrator',[]);}return h;}const MAX_RISK_REMINDERS=0xa;function collectRiskReminders(a,b){try{return runAnalyzers(a,{'kinds':['risk']})['filter'](c=>c['roles']['includes'](b)||c['roles']['includes']('neutral'))['sort']((c,d)=>SEVERITY_RANK[d['severity']]-SEVERITY_RANK[c['severity']])['slice'](0x0,MAX_RISK_REMINDERS);}catch{return[];}}export function buildRoleInterest(a,b,c,d){const e=b['toLowerCase'](),f=VIEWER_OF[c],g=buildViewport(a,e,f),h=buildControlIndex(g),i=heldPermissionIndices(g,e),j=collectStakes(g,e,h,i),k=collectActions(g,e,c,d,j,i),l=collectArbActions(g,e,d,j),m=collectCounterparties(g,e,c,d,j,h),n=collectRiskReminders(g,f),o=k['find'](y=>y['advice']['actions']['length']>0x0)?.['advice']['actions'][0x0],p=m['find'](y=>y['alignment']==='conflict'),q='Viewing\x20'+e+'\x20as\x20'+c+':\x20'+(j['length']+'\x20stake(s)\x20in\x20flight\x20('+j['map'](y=>y['object_type']+':'+y['positions']['join']('/'))['slice'](0x0,0x4)['join'](',\x20')+(j['length']>0x4?'\x20etc.':'')+');\x20')+(o?'the\x20best\x20currently\x20operable\x20action\x20is\x20\x27'+o['forward']+'\x27\x20on\x20order\x20'+(k['find'](y=>y['advice']['actions'][0x0]===o)?.['order']??'')+'\x20('+o['payoff_note']+');\x20':k['length']>0x0?'orders\x20in\x20flight\x20but\x20no\x20action\x20operable\x20from\x20this\x20view\x20(waiting\x20on\x20others\x20or\x20off-chain\x20resolution);\x20':'no\x20operable\x20in-flight\x20orders;\x20')+(l['length']>0x0?l['length']+'\x20arbitration\x20case\x20action\x20suggestion(s);\x20':'')+(p?'largest\x20structural\x20counterparty\x20tension:\x20'+p['counter_role']+'\x20('+p['note']+')':'no\x20notable\x20counterparty\x20tension')+(n['length']>0x0?'\x20'+n['length']+'\x20role-relevant\x20risk\x20reminder(s).':''),r={'role':c,'observer':e,...d&&(d['risk_appetite']||d['requirements']?.['length'])?{'drive':d}:{},'stakes':j,'actions':k,'arb_actions':l,'counterparties':m,'risk_finding_ids':n['map'](y=>y['id']),'summary':q},s=g['visibleEdges']['filter'](y=>['eoa.order','service.order','demand.presenter','arb.voter','order.dispute']['includes'](y['schema'])),{confidence:t,window:u}=pathConfidence(g,s),w=n['length']>0x0&&SEVERITY_RANK[n[0x0]['severity']]>=SEVERITY_RANK['medium']?n[0x0]['severity']:'info',x={'id':'IR:'+c+':'+e,'kind':'game','severity':w,'title':'Role\x20interest\x20view\x20('+c+'):\x20'+j['length']+'\x20stake(s)\x20in\x20flight'+(o?',\x20best\x20action\x20\x27'+o['forward']+'\x27':''),'path':[e,...j['map'](y=>y['object'])],'confidence':t,...u?{'window':u}:{},'roles':[f],'detail':q,'suggestion':o?'Execute\x20in\x20advice\x20order\x20(\x27'+o['forward']+'\x27\x20'+(o['guard']?'requires\x20Guard\x20passport\x20verification\x20first\x20and\x20':'')+'goes\x20through\x20the\x20tool\x20routing\x20in\x20recommended_calls);\x20see\x20the\x20payload\x20for\x20counterparty\x20tension\x20and\x20risk\x20reminders.':'When\x20no\x20action\x20is\x20operable:\x20watch\x20blocked_forwards\x20waiting\x20conditions\x20and\x20counterparty\x20tension\x20changes,\x20or\x20re-project\x20with\x20a\x20different\x20role/context_account.','interest':r};return{'finding':x,'view':r};}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{describe,expect,it}from'vitest';import{buildRoleInterest,toCommercialRole,viewerRoleOf}from'./interest.js';function mkNode(a,b,c){return{'id':a['toLowerCase'](),'kind':b?'object':'eoa',...b?{'objectType':b}:{},...c?{'raw':{'object':a,'data':c}}:{},'state':'fetched','origins':[{'depth':0x0}],'depth':0x0};}function mkEdge(a,b,c,d,e,f='complete'){return{'id':a+'|'+c['toLowerCase']()+'→'+d['toLowerCase'](),'schema':a,'family':b,'from':c['toLowerCase'](),'to':d['toLowerCase'](),'retention':f,'evidence':'spec','observedAt':0x0,...e?{'payload':e}:{}};}function mkGraph(a,b){const c=new Map(),d=new Map(),f=(g,h,i)=>{const j=g['get'](h)??[];j['push'](i),g['set'](h,j);};for(const g of b){f(c,g['from'],g),f(d,g['to'],g);}return{'network':'testnet','seed':'spec','builtAt':0x0,'nodes':new Map(a['map'](h=>[h['id'],h])),'edges':b,'out':c,'inc':d,'gaps':[],'truncations':[],'rpcReport':{'batches':0x0,'byChannel':{'objects':0x0,'keyedFields':0x0,'tables':0x0,'events':0x0},'dedupHits':0x0},'budgetExhausted':{}};}const CUSTOMER='00customer',MERCHANT='00merchant',ARB_EOA='00arb',DEMANDER='00demander',SUPPLIER='00supplier',SERVICE='0xservice',MACHINE='0xmachine',PROGRESS='0xprogress',ORDER='0xorder1',ALLOC='0xalloc',PERM_M='0xpermm',PERM_A='0xperma',PERM_D='0xpermd',ARB_SVC='0xarbsvc',ARB_CASE='0xarbcase',DEMAND='0xdemand';function machineEdges(a=MACHINE){const b=a['toLowerCase']();return[mkEdge('machine.node','W',b,b+'::node::shipping'),mkEdge('machine.node','W',b,b+'::node::done'),mkEdge('machine.node','W',b,b+'::node::refunded'),mkEdge('machine.node','W',b,b+'::node::pack'),mkEdge('wf.transition','W',b+'::node::shipping',b+'::node::done',{'node':'done','prevNode':'shipping','forward':'confirm','namedOperator':''}),mkEdge('wf.transition','W',b+'::node::shipping',b+'::node::refunded',{'node':'refunded','prevNode':'shipping','forward':'cancel','namedOperator':''}),mkEdge('wf.transition','W',b+'::node::shipping',b+'::node::pack',{'node':'pack','prevNode':'shipping','forward':'op','permissionIndex':0x7,'threshold':0x2,'weight':0x1})];}function orderGraphNodes(){return[mkNode(CUSTOMER),mkNode(MERCHANT),mkNode(SERVICE,'Service',{'compensation_fund':'500','bPublished':!![]}),mkNode(MACHINE,'Machine'),mkNode(PROGRESS,'Progress',{'current':'shipping','machine':MACHINE}),mkNode(ORDER,'Order',{'amount':'1000','builder':CUSTOMER,'service':SERVICE,'machine':MACHINE,'progress':PROGRESS}),mkNode(ALLOC,'Allocation',{'allocators':[{'guard':'0x0','sharing':[{'who':{'Entity':MERCHANT},'sharing':'10000','mode':0x1},{'who':'Signer','sharing':'0','mode':0x0},{'who':{'GuardIdentifier':0x1},'sharing':'0','mode':0x0}]}]}),mkNode(PERM_M,'Permission')];}function orderGraphEdges(){return[...machineEdges(),mkEdge('eoa.order','R',CUSTOMER,ORDER,undefined,'bounded_window'),mkEdge('order.builder','F',ORDER,CUSTOMER),mkEdge('order.service','F',ORDER,SERVICE),mkEdge('order.machine','F',ORDER,MACHINE),mkEdge('order.progress','F',ORDER,PROGRESS),mkEdge('order.allocation','F',ORDER,ALLOC),mkEdge('eoa.permission','R',MERCHANT,PERM_M,{'roleBits':0x1}),mkEdge('permission.core_binding','F',PERM_M,SERVICE),mkEdge('service.order','R',SERVICE,'0xorder2',undefined,'bounded_window'),mkEdge('order.builder','F','0xorder2','00someoneelse')];}describe('role\x20coordinate\x20mapping\x20(single\x20system)',()=>{it('maps\x20the\x20viewport\x20alias\x20and\x20persona\x20roles\x20onto\x20CommercialRole',()=>{expect(toCommercialRole('buyer'))['toBe']('customer'),expect(toCommercialRole('customer'))['toBe']('customer'),expect(toCommercialRole('demander'))['toBe']('demander'),expect(toCommercialRole('merchant'))['toBe']('merchant'),expect(toCommercialRole('arbitrator'))['toBe']('arbitrator'),expect(toCommercialRole('who-knows'))['toBe']('neutral');}),it('maps\x20every\x20CommercialRole\x20onto\x20a\x20viewer\x20role',()=>{expect(viewerRoleOf('customer'))['toBe']('buyer'),expect(viewerRoleOf('demander'))['toBe']('demander'),expect(viewerRoleOf('neutral'))['toBe']('neutral');});}),describe('buildRoleInterest\x20—\x20customer',()=>{const a=mkGraph(orderGraphNodes(),orderGraphEdges());it('projects\x20buyer\x20stakes\x20with\x20amount\x20and\x20completion\x20state',()=>{const {view:b}=buildRoleInterest(a,CUSTOMER,'customer'),c=b['stakes']['find'](d=>d['object']===ORDER);expect(c)['toBeDefined'](),expect(c['positions'])['toContain']('buyer'),expect(c['amount'])['toBe']('1000'),expect(c['state'])['toBe']('in_progress'),expect(b['stakes']['some'](d=>d['object']==='0xorder2'))['toBe'](![]);}),it('ranks\x20operable\x20forwards\x20via\x20node-game\x20(order_holder\x20path)',()=>{const {view:b}=buildRoleInterest(a,CUSTOMER,'customer');expect(b['actions'])['toHaveLength'](0x1);const c=b['actions'][0x0];expect(c['order'])['toBe'](ORDER),expect(c['current_node'])['toBe']('shipping');const d=c['advice']['actions']['map'](e=>e['forward']);expect(d)['toContain']('confirm'),expect(d)['toContain']('cancel'),expect(c['advice']['actions'][0x0]['forward'])['toBe']('cancel'),expect(c['advice']['actions'][0x0]['execution_path'])['toBe']('order_holder'),expect(c['blocked_forwards']['map'](e=>e['forward']))['toContain']('op'),expect(c['recommended_calls']['length'])['toBeGreaterThan'](0x0),expect(c['recommended_calls'][0x0]['call']['tool'])['toBe']('onchain_operations');}),it('derives\x20merchant\x20counterparty\x20tension\x20from\x20ROLE_INTERESTS\x20(conflict)',()=>{const {view:b}=buildRoleInterest(a,CUSTOMER,'customer'),c=b['counterparties']['find'](d=>d['counter_role']==='merchant');expect(c)['toBeDefined'](),expect(c['alignment'])['toBe']('conflict'),expect(c['their_prefer'])['toContain']('fund_released_to_merchant');}),it('emits\x20one\x20IR\x20finding\x20carrying\x20the\x20structured\x20payload',()=>{const {finding:b,view:c}=buildRoleInterest(a,CUSTOMER,'customer');expect(b['id'])['toBe']('IR:customer:'+CUSTOMER),expect(b['kind'])['toBe']('game'),expect(b['interest'])['toBe'](c),expect(b['path'][0x0])['toBe'](CUSTOMER),expect(b['confidence'])['toBe']('windowed');}),it('re-anchors\x20scoring\x20with\x20a\x20conservative\x20persona\x20drive',()=>{const b=buildRoleInterest(a,CUSTOMER,'customer')['view'],c=buildRoleInterest(a,CUSTOMER,'customer',{'risk_appetite':'conservative'})['view'],d=b['actions'][0x0]['advice']['actions']['find'](f=>f['forward']==='confirm'),e=c['actions'][0x0]['advice']['actions']['find'](f=>f['forward']==='confirm');expect(e['risk_score'])['toBeGreaterThan'](d['risk_score']),expect(e['favorability'])['toBeLessThan'](d['favorability']);});}),describe('buildRoleInterest\x20—\x20merchant',()=>{const a=[...orderGraphNodes(),mkNode('0xorder2','Order',{'amount':'2000','builder':'00someoneelse','service':SERVICE,'machine':MACHINE,'progress':PROGRESS}),mkNode('00someoneelse')],b=[...orderGraphEdges()['filter'](d=>!(d['schema']==='order.builder'&&d['from']==='0xorder2')),mkEdge('order.builder','F','0xorder2','00someoneelse'),mkEdge('service.order','R',SERVICE,ORDER,undefined,'bounded_window'),mkEdge('permission.entity','W',PERM_M,MERCHANT,{'permIndices':[0x7]})],c=mkGraph(a,b);it('projects\x20controller\x20+\x20seller\x20stakes',()=>{const {view:d}=buildRoleInterest(c,MERCHANT,'merchant'),e=d['stakes']['find'](g=>g['object']===SERVICE);expect(e?.['positions'])['toContain']('controller');const f=d['stakes']['find'](g=>g['object']===ORDER);expect(f?.['positions'])['toContain']('seller');}),it('executes\x20permission-gated\x20forwards\x20only\x20(OrderHolder\x20forwards\x20stay\x20blocked)',()=>{const {view:d}=buildRoleInterest(c,MERCHANT,'merchant'),e=d['actions']['find'](h=>h['order']===ORDER);expect(e)['toBeDefined']();const f=e['advice']['actions']['find'](g=>g['forward']==='op');expect(f)['toBeDefined'](),expect(f['execution_path'])['toBe']('permission'),expect(e['recommended_calls']['find'](g=>g['forward']==='op')['call']['tool'])['toBe']('workflow_operation'),expect(e['blocked_forwards']['map'](g=>g['forward'])['sort']())['toEqual'](['cancel','confirm']),expect(e['advice']['actions'])['toHaveLength'](0x1),expect(e['advice']['actions'][0x0]['forward'])['toBe']('op'),expect(e['advice']['actions'][0x0]['is_optimal'])['toBe'](!![]);}),it('projects\x20the\x20allocation\x20waterfall\x20(direct_to_me\x20slots)',()=>{const {view:d}=buildRoleInterest(c,MERCHANT,'merchant'),e=d['actions']['find'](h=>h['order']===ORDER),f=e['advice']['cooperation'];expect(f)['toBeDefined'](),expect(f['needed_from_others'])['toBeGreaterThan'](0x0);}),it('surfaces\x20role-relevant\x20R/AC\x20risk\x20reminders\x20(R2\x20exposure\x20fires\x20for\x20the\x20merchant\x20view)',()=>{const {view:d,finding:e}=buildRoleInterest(c,MERCHANT,'merchant');expect(d['risk_finding_ids']['some'](f=>f['startsWith']('R2:')))['toBe'](!![]),expect(e['severity'])['toBe']('high');});}),describe('buildRoleInterest\x20—\x20demander',()=>{const a=[mkNode(DEMANDER),mkNode(SUPPLIER),mkNode(PERM_D,'Permission'),mkNode(DEMAND,'Demand',{'description':'car\x20wash\x20in\x20london'})],b=[mkEdge('eoa.permission','R',DEMANDER,PERM_D,{'roleBits':0x1}),mkEdge('demand.permission','F',DEMAND,PERM_D),mkEdge('demand.presenter','R',DEMAND,SUPPLIER),mkEdge('demand.permission','F','0xdemand2','0xpermother')],c=mkGraph(a,b);it('anchors\x20own\x20demands\x20through\x20the\x20permission\x20(demand_owner\x20stake,\x20presenter\x20count)',()=>{const {view:d}=buildRoleInterest(c,DEMANDER,'demander'),e=d['stakes']['find'](f=>f['object']===DEMAND);expect(e)['toBeDefined'](),expect(e['positions'])['toContain']('demand_owner'),expect(e['state'])['toBe']('1\x20presenter(s)'),expect(d['stakes']['some'](f=>f['object']==='0xdemand2'))['toBe'](![]);});}),describe('buildRoleInterest\x20—\x20arbitrator',()=>{const a=[mkNode(ARB_EOA),mkNode(PERM_A,'Permission'),mkNode(ARB_SVC,'Arbitration',{'voting_guard':[]}),mkNode(ARB_CASE,'Arb',{'status':'Voting','order':ORDER}),...orderGraphNodes()],b=[mkEdge('eoa.permission','R',ARB_EOA,PERM_A,{'roleBits':0x1}),mkEdge('permission.core_binding','F',PERM_A,ARB_SVC),mkEdge('arb.arbitration_service','F',ARB_CASE,ARB_SVC),mkEdge('arb.voter','S',ARB_CASE,ARB_EOA,{'weight':0x1}),...orderGraphEdges()],c=mkGraph(a,b);it('collects\x20voter\x20stakes\x20and\x20arbitration-game\x20advice\x20(Voting\x20→\x20vote\x20is\x20optimal)',()=>{const {view:d}=buildRoleInterest(c,ARB_EOA,'arbitrator'),e=d['stakes']['find'](f=>f['object']===ARB_CASE);expect(e?.['positions'])['toContain']('voter'),expect(e?.['positions'])['toContain']('arbitration_owner'),expect(e?.['state'])['toBe']('Voting'),expect(d['arb_actions'])['toHaveLength'](0x1),expect(d['arb_actions'][0x0]['perspective'])['toBe']('arbitrator'),expect(d['arb_actions'][0x0]['actions'][0x0]['action'])['toBe']('vote'),expect(d['arb_actions'][0x0]['actions'][0x0]['is_optimal'])['toBe'](!![]);});}),describe('buildRoleInterest\x20—\x20prospect\x20(no\x20on-chain\x20stake)',()=>{it('returns\x20an\x20honest\x20empty\x20view\x20instead\x20of\x20guessing',()=>{const a=mkGraph(orderGraphNodes(),orderGraphEdges()),{view:b,finding:c}=buildRoleInterest(a,'00stranger','prospect');expect(b['stakes'])['toHaveLength'](0x0),expect(b['actions'])['toHaveLength'](0x0),expect(c['interest'])['toBe'](b),expect(c['kind'])['toBe']('game');});});
|
|
1
|
+
import{describe,expect,it}from'vitest';import{buildRoleInterest,toCommercialRole,viewerRoleOf}from'./interest.js';function mkNode(a,b,c){return{'id':a['toLowerCase'](),'kind':b?'object':'eoa',...b?{'objectType':b}:{},...c?{'raw':{'object':a,'data':c}}:{},'state':'fetched','origins':[{'depth':0x0}],'depth':0x0};}function mkEdge(a,b,c,d,e,f='complete'){return{'id':a+'|'+c['toLowerCase']()+'→'+d['toLowerCase'](),'schema':a,'family':b,'from':c['toLowerCase'](),'to':d['toLowerCase'](),'retention':f,'observedAt':0x0,...e?{'payload':e}:{}};}function mkGraph(a,b){const c=new Map(),d=new Map(),f=(g,h,i)=>{const j=g['get'](h)??[];j['push'](i),g['set'](h,j);};for(const g of b){f(c,g['from'],g),f(d,g['to'],g);}return{'network':'testnet','seed':'spec','builtAt':0x0,'nodes':new Map(a['map'](h=>[h['id'],h])),'edges':b,'out':c,'inc':d,'gaps':[],'truncations':[],'rpcReport':{'batches':0x0,'byChannel':{'objects':0x0,'keyedFields':0x0,'tables':0x0,'events':0x0},'dedupHits':0x0},'budgetExhausted':{}};}const CUSTOMER='00customer',MERCHANT='00merchant',ARB_EOA='00arb',DEMANDER='00demander',SUPPLIER='00supplier',SERVICE='0xservice',MACHINE='0xmachine',PROGRESS='0xprogress',ORDER='0xorder1',ALLOC='0xalloc',PERM_M='0xpermm',PERM_A='0xperma',PERM_D='0xpermd',ARB_SVC='0xarbsvc',ARB_CASE='0xarbcase',DEMAND='0xdemand';function machineEdges(a=MACHINE){const b=a['toLowerCase']();return[mkEdge('machine.node','W',b,b+'::node::shipping'),mkEdge('machine.node','W',b,b+'::node::done'),mkEdge('machine.node','W',b,b+'::node::refunded'),mkEdge('machine.node','W',b,b+'::node::pack'),mkEdge('wf.transition','W',b+'::node::shipping',b+'::node::done',{'node':'done','prevNode':'shipping','forward':'confirm','namedOperator':''}),mkEdge('wf.transition','W',b+'::node::shipping',b+'::node::refunded',{'node':'refunded','prevNode':'shipping','forward':'cancel','namedOperator':''}),mkEdge('wf.transition','W',b+'::node::shipping',b+'::node::pack',{'node':'pack','prevNode':'shipping','forward':'op','permissionIndex':0x7,'threshold':0x2,'weight':0x1})];}function orderGraphNodes(){return[mkNode(CUSTOMER),mkNode(MERCHANT),mkNode(SERVICE,'Service',{'compensation_fund':'500','bPublished':!![]}),mkNode(MACHINE,'Machine'),mkNode(PROGRESS,'Progress',{'current':'shipping','machine':MACHINE}),mkNode(ORDER,'Order',{'amount':'1000','builder':CUSTOMER,'service':SERVICE,'machine':MACHINE,'progress':PROGRESS}),mkNode(ALLOC,'Allocation',{'allocators':[{'guard':'0x0','sharing':[{'who':{'Entity':MERCHANT},'sharing':'10000','mode':0x1},{'who':'Signer','sharing':'0','mode':0x0},{'who':{'GuardIdentifier':0x1},'sharing':'0','mode':0x0}]}]}),mkNode(PERM_M,'Permission')];}function orderGraphEdges(){return[...machineEdges(),mkEdge('eoa.order','R',CUSTOMER,ORDER,undefined,'bounded_window'),mkEdge('order.builder','F',ORDER,CUSTOMER),mkEdge('order.service','F',ORDER,SERVICE),mkEdge('order.machine','F',ORDER,MACHINE),mkEdge('order.progress','F',ORDER,PROGRESS),mkEdge('order.allocation','F',ORDER,ALLOC),mkEdge('eoa.permission','R',MERCHANT,PERM_M,{'roleBits':0x1}),mkEdge('permission.core_binding','F',PERM_M,SERVICE),mkEdge('service.order','R',SERVICE,'0xorder2',undefined,'bounded_window'),mkEdge('order.builder','F','0xorder2','00someoneelse')];}describe('role\x20coordinate\x20mapping\x20(single\x20system)',()=>{it('maps\x20the\x20viewport\x20alias\x20and\x20persona\x20roles\x20onto\x20CommercialRole',()=>{expect(toCommercialRole('buyer'))['toBe']('customer'),expect(toCommercialRole('customer'))['toBe']('customer'),expect(toCommercialRole('demander'))['toBe']('demander'),expect(toCommercialRole('merchant'))['toBe']('merchant'),expect(toCommercialRole('arbitrator'))['toBe']('arbitrator'),expect(toCommercialRole('who-knows'))['toBe']('neutral');}),it('maps\x20every\x20CommercialRole\x20onto\x20a\x20viewer\x20role',()=>{expect(viewerRoleOf('customer'))['toBe']('buyer'),expect(viewerRoleOf('demander'))['toBe']('demander'),expect(viewerRoleOf('neutral'))['toBe']('neutral');});}),describe('buildRoleInterest\x20—\x20customer',()=>{const a=mkGraph(orderGraphNodes(),orderGraphEdges());it('projects\x20buyer\x20stakes\x20with\x20amount\x20and\x20completion\x20state',()=>{const {view:b}=buildRoleInterest(a,CUSTOMER,'customer'),c=b['stakes']['find'](d=>d['object']===ORDER);expect(c)['toBeDefined'](),expect(c['positions'])['toContain']('buyer'),expect(c['amount'])['toBe']('1000'),expect(c['state'])['toBe']('in_progress'),expect(b['stakes']['some'](d=>d['object']==='0xorder2'))['toBe'](![]);}),it('ranks\x20operable\x20forwards\x20via\x20node-game\x20(order_holder\x20path)',()=>{const {view:b}=buildRoleInterest(a,CUSTOMER,'customer');expect(b['actions'])['toHaveLength'](0x1);const c=b['actions'][0x0];expect(c['order'])['toBe'](ORDER),expect(c['current_node'])['toBe']('shipping');const d=c['advice']['actions']['map'](e=>e['forward']);expect(d)['toContain']('confirm'),expect(d)['toContain']('cancel'),expect(c['advice']['actions'][0x0]['forward'])['toBe']('cancel'),expect(c['advice']['actions'][0x0]['execution_path'])['toBe']('order_holder'),expect(c['blocked_forwards']['map'](e=>e['forward']))['toContain']('op'),expect(c['recommended_calls']['length'])['toBeGreaterThan'](0x0),expect(c['recommended_calls'][0x0]['call']['tool'])['toBe']('onchain_operations');}),it('derives\x20merchant\x20counterparty\x20tension\x20from\x20the\x20role-interests\x20table\x20(conflict)',()=>{const {view:b}=buildRoleInterest(a,CUSTOMER,'customer'),c=b['counterparties']['find'](d=>d['counter_role']==='merchant');expect(c)['toBeDefined'](),expect(c['alignment'])['toBe']('conflict'),expect(c['their_prefer'])['toContain']('fund_released_to_merchant');}),it('emits\x20one\x20IR\x20finding\x20carrying\x20the\x20structured\x20payload',()=>{const {finding:b,view:c}=buildRoleInterest(a,CUSTOMER,'customer');expect(b['id'])['toBe']('IR:customer:'+CUSTOMER),expect(b['kind'])['toBe']('game'),expect(b['interest'])['toBe'](c),expect(b['path'][0x0])['toBe'](CUSTOMER),expect(b['confidence'])['toBe']('windowed');}),it('re-anchors\x20scoring\x20with\x20a\x20conservative\x20persona\x20drive',()=>{const b=buildRoleInterest(a,CUSTOMER,'customer')['view'],c=buildRoleInterest(a,CUSTOMER,'customer',{'risk_appetite':'conservative'})['view'],d=b['actions'][0x0]['advice']['actions']['find'](f=>f['forward']==='confirm'),e=c['actions'][0x0]['advice']['actions']['find'](f=>f['forward']==='confirm');expect(e['risk_score'])['toBeGreaterThan'](d['risk_score']),expect(e['favorability'])['toBeLessThan'](d['favorability']);});}),describe('buildRoleInterest\x20—\x20merchant',()=>{const a=[...orderGraphNodes(),mkNode('0xorder2','Order',{'amount':'2000','builder':'00someoneelse','service':SERVICE,'machine':MACHINE,'progress':PROGRESS}),mkNode('00someoneelse')],b=[...orderGraphEdges()['filter'](d=>!(d['schema']==='order.builder'&&d['from']==='0xorder2')),mkEdge('order.builder','F','0xorder2','00someoneelse'),mkEdge('service.order','R',SERVICE,ORDER,undefined,'bounded_window'),mkEdge('permission.entity','W',PERM_M,MERCHANT,{'permIndices':[0x7]})],c=mkGraph(a,b);it('projects\x20controller\x20+\x20seller\x20stakes',()=>{const {view:d}=buildRoleInterest(c,MERCHANT,'merchant'),e=d['stakes']['find'](g=>g['object']===SERVICE);expect(e?.['positions'])['toContain']('controller');const f=d['stakes']['find'](g=>g['object']===ORDER);expect(f?.['positions'])['toContain']('seller');}),it('executes\x20permission-gated\x20forwards\x20only\x20(OrderHolder\x20forwards\x20stay\x20blocked)',()=>{const {view:d}=buildRoleInterest(c,MERCHANT,'merchant'),e=d['actions']['find'](h=>h['order']===ORDER);expect(e)['toBeDefined']();const f=e['advice']['actions']['find'](g=>g['forward']==='op');expect(f)['toBeDefined'](),expect(f['execution_path'])['toBe']('permission'),expect(e['recommended_calls']['find'](g=>g['forward']==='op')['call']['tool'])['toBe']('workflow_operation'),expect(e['blocked_forwards']['map'](g=>g['forward'])['sort']())['toEqual'](['cancel','confirm']),expect(e['advice']['actions'])['toHaveLength'](0x1),expect(e['advice']['actions'][0x0]['forward'])['toBe']('op'),expect(e['advice']['actions'][0x0]['is_optimal'])['toBe'](!![]);}),it('projects\x20the\x20allocation\x20waterfall\x20(direct_to_me\x20slots)',()=>{const {view:d}=buildRoleInterest(c,MERCHANT,'merchant'),e=d['actions']['find'](h=>h['order']===ORDER),f=e['advice']['cooperation'];expect(f)['toBeDefined'](),expect(f['needed_from_others'])['toBeGreaterThan'](0x0);}),it('surfaces\x20role-relevant\x20R/AC\x20risk\x20reminders\x20(R2\x20exposure\x20fires\x20for\x20the\x20merchant\x20view)',()=>{const {view:d,finding:e}=buildRoleInterest(c,MERCHANT,'merchant');expect(d['risk_finding_ids']['some'](f=>f['startsWith']('R2:')))['toBe'](!![]),expect(e['severity'])['toBe']('high');});}),describe('buildRoleInterest\x20—\x20demander',()=>{const a=[mkNode(DEMANDER),mkNode(SUPPLIER),mkNode(PERM_D,'Permission'),mkNode(DEMAND,'Demand',{'description':'car\x20wash\x20in\x20london'})],b=[mkEdge('eoa.permission','R',DEMANDER,PERM_D,{'roleBits':0x1}),mkEdge('demand.permission','F',DEMAND,PERM_D),mkEdge('demand.presenter','R',DEMAND,SUPPLIER),mkEdge('demand.permission','F','0xdemand2','0xpermother')],c=mkGraph(a,b);it('anchors\x20own\x20demands\x20through\x20the\x20permission\x20(demand_owner\x20stake,\x20presenter\x20count)',()=>{const {view:d}=buildRoleInterest(c,DEMANDER,'demander'),e=d['stakes']['find'](f=>f['object']===DEMAND);expect(e)['toBeDefined'](),expect(e['positions'])['toContain']('demand_owner'),expect(e['state'])['toBe']('1\x20presenter(s)'),expect(d['stakes']['some'](f=>f['object']==='0xdemand2'))['toBe'](![]);});}),describe('buildRoleInterest\x20—\x20arbitrator',()=>{const a=[mkNode(ARB_EOA),mkNode(PERM_A,'Permission'),mkNode(ARB_SVC,'Arbitration',{'voting_guard':[]}),mkNode(ARB_CASE,'Arb',{'status':'Voting','order':ORDER}),...orderGraphNodes()],b=[mkEdge('eoa.permission','R',ARB_EOA,PERM_A,{'roleBits':0x1}),mkEdge('permission.core_binding','F',PERM_A,ARB_SVC),mkEdge('arb.arbitration_service','F',ARB_CASE,ARB_SVC),mkEdge('arb.voter','S',ARB_CASE,ARB_EOA,{'weight':0x1}),...orderGraphEdges()],c=mkGraph(a,b);it('collects\x20voter\x20stakes\x20and\x20arbitration-game\x20advice\x20(Voting\x20→\x20vote\x20is\x20optimal)',()=>{const {view:d}=buildRoleInterest(c,ARB_EOA,'arbitrator'),e=d['stakes']['find'](f=>f['object']===ARB_CASE);expect(e?.['positions'])['toContain']('voter'),expect(e?.['positions'])['toContain']('arbitration_owner'),expect(e?.['state'])['toBe']('Voting'),expect(d['arb_actions'])['toHaveLength'](0x1),expect(d['arb_actions'][0x0]['perspective'])['toBe']('arbitrator'),expect(d['arb_actions'][0x0]['actions'][0x0]['action'])['toBe']('vote'),expect(d['arb_actions'][0x0]['actions'][0x0]['is_optimal'])['toBe'](!![]);});}),describe('buildRoleInterest\x20—\x20prospect\x20(no\x20on-chain\x20stake)',()=>{it('returns\x20an\x20honest\x20empty\x20view\x20instead\x20of\x20guessing',()=>{const a=mkGraph(orderGraphNodes(),orderGraphEdges()),{view:b,finding:c}=buildRoleInterest(a,'00stranger','prospect');expect(b['stakes'])['toHaveLength'](0x0),expect(b['actions'])['toHaveLength'](0x0),expect(c['interest'])['toBe'](b),expect(c['kind'])['toBe']('game');});});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const WF_NODE_MARK='::node::';export function shortAddress(a){const b=a['trim']();if(!b['startsWith']('0x')||b['length']<0xe)return b;
|
|
1
|
+
const WF_NODE_MARK='::node::';export function shortAddress(a){const b=a['trim']();if(!b['startsWith']('0x')||b['length']<0xe)return b;const c=b['slice'](0x2);return(c['slice'](0x0,0x4)+'-'+c['slice'](-0x3))['toUpperCase']();}export function isWfNodeId(a){return a['includes'](WF_NODE_MARK);}export function wfMachineOf(a){const b=a['indexOf'](WF_NODE_MARK);return b>=0x0?a['slice'](0x0,b):'';}export function wfNodeName(a){const b=a['indexOf'](WF_NODE_MARK);return b>=0x0?a['slice'](b+WF_NODE_MARK['length']):a;}const TYPE_TAG_RE=/^(0x[0-9a-fA-F]+)::([A-Za-z0-9_]+)::([A-Za-z0-9_]+)(?:<(.*)>)?$/;export function humanizeTypeTag(a){const b=TYPE_TAG_RE['exec'](a['trim']());if(!b)return null;const [,,,c,d]=b;if(!d)return c;const e=[];let f=0x0,g='';for(const i of d){if(i==='<')f++;else{if(i==='>')f--;}if(i===','&&f===0x0)e['push'](g['trim']()),g='';else g+=i;}if(g['trim']())e['push'](g['trim']());const h=e['map'](j=>humanizeTypeTag(j)??j);return h['length']?c+'<'+h['join'](',\x20')+'>':c;}export function humanizeStoredName(a){const b=humanizeTypeTag(a);return b?{'label':b,'full':a}:{'label':a};}function rootData(a){if(!a||typeof a!=='object')return undefined;const b=a,c=b['data']??b;return c&&typeof c==='object'?c:undefined;}export function buildNameIndex(a){const b=new Map();for(const c of a['nodes']['values']()){if(c['kind']!=='object'||!c['raw'])continue;const e=rootData(c['raw']),f=e?.['name'];if(typeof f==='string'&&f['trim']())b['set'](c['id'],f['trim']());}return{'objects':b};}export function createNameResolver(a){const b=d=>{const e=a['objects']['get'](d);return e?{'label':e}:{'label':shortAddress(d),'full':d};},c=d=>{if(isWfNodeId(d)){const e=wfMachineOf(d),f=humanizeStoredName(wfNodeName(d)),g=a['objects']['get'](e);if(g)return{'label':g+'\x20›\x20'+f['label'],'full':f['full']};return f;}if(d['startsWith']('0x')&&d['length']>=0xe)return b(d['toLowerCase']());return{'label':d};};return{'resolve':c,'resolveWf'(d){if(!isWfNodeId(d))return undefined;return{'machine':b(wfMachineOf(d)),'node':humanizeStoredName(wfNodeName(d))};}};}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{describe,expect,it}from'vitest';import{ENTRYPOINT}from'@wowok/wowok';import{findingWhereResolved}from'./analyze.js';import{buildNameIndex,createNameResolver,humanizeStoredName,humanizeTypeTag,shortAddress}from'./names.js';const MACHINE='0x14b474d65159538031a75d37e4eb2367971fd30743df75e4472894be4f3c0e8f',TYPE_TAG_NODE='0x2::machine::Node<0x2::wow::WOW>';function graphWith(a){return{'network':ENTRYPOINT['Mainnet'],'seed':MACHINE,'builtAt':0x1,'nodes':new Map(a['map'](b=>[b['id'],b])),'edges':[],'out':new Map(),'inc':new Map(),'gaps':[],'truncations':[],'rpcReport':{'batches':0x0,'byChannel':{'objects':0x0,'keyedFields':0x0,'tables':0x0,'events':0x0},'dedupHits':0x0},'budgetExhausted':{}};}function objectNode(a,b){return{'id':a,'kind':'object','objectType':'Machine','state':'fetched','origins':[],'depth':0x0,'raw':{'object':a,'type':'Machine',...b!==undefined?{'data':{'name':b}}:{}}};}describe('humanizeTypeTag',()=>{it('shortens\x20a\x20Move\x20type\x20tag\x20to\x20its\x20struct\x20+\x20generic-param\x20last\x20segments',()=>{expect(humanizeTypeTag(TYPE_TAG_NODE))['toBe']('Node<WOW>'),expect(humanizeTypeTag('0x2::machine::Node'))['toBe']('Node');}),it('passes\x20plain\x20business\x20names\x20through\x20as\x20null',()=>{expect(humanizeTypeTag('Order\x20Confirmed'))['toBeNull'](),expect(humanizeTypeTag('paid'))['toBeNull']();}),it('keeps\x20nested\x20generics\x20depth-correct',()=>{expect(humanizeTypeTag('0x1::a::Box<0x2::b::C<0x3::d::E>,\x200x4::f::G>'))['toBe']('Box<C<E>,\x20G>');});}),describe('humanizeStoredName',()=>{it('carries\x20the\x20verbatim\x20tag\x20as\x20full\x20when\x20humanized',()=>{expect(humanizeStoredName(TYPE_TAG_NODE))['toEqual']({'label':'Node<WOW>','full':TYPE_TAG_NODE}),expect(humanizeStoredName('Order\x20Confirmed'))['toEqual']({'label':'Order\x20Confirmed'});});}),describe('buildNameIndex\x20+\x20createNameResolver',()=>{it('resolves\x20named\x20machines\x20by\x20on-chain\x20name\x20and\x20unnamed\x20to\x20a\x20short\x20address',()=>{const a='0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',b=graphWith([objectNode(MACHINE,'travel_shop_machine'),objectNode(a)]),c=createNameResolver(buildNameIndex(b));expect(c['resolve'](MACHINE)['label'])['toBe']('travel_shop_machine');const d=c['resolve'](a);expect(d['label'])['toBe'](shortAddress(a)),expect(d['full'])['toBe'](a);}),it('resolves\x20synthetic\x20wf\x20node\x20ids:\x20machine\x20name\x20+\x20humanized\x20type-tag\x20node\x20(AC-6)',()=>{const a=graphWith([objectNode(MACHINE,'travel_shop_machine')]),b=createNameResolver(buildNameIndex(a)),c=MACHINE+'::node::'+TYPE_TAG_NODE,d=b['resolveWf'](c);expect(d['machine']['label'])['toBe']('travel_shop_machine'),expect(d['node'])['toEqual']({'label':'Node<WOW>','full':TYPE_TAG_NODE}),expect(b['resolve'](c)['label'])['toContain']('Node<WOW>'),expect(b['resolve'](c)['label'])['not']['toContain']('::node::');}),it('findingWhereResolved\x20renders\x20machine\x20name\x20+\x20node\x20labels\x20in\x20R4\x20lines',()=>{const a=graphWith([objectNode(MACHINE,'travel_shop_machine')]),b=createNameResolver(buildNameIndex(a)),c='R4:'+MACHINE+':'+MACHINE+'::node::'+TYPE_TAG_NODE+'→'+MACHINE+'::node::'+TYPE_TAG_NODE,d=findingWhereResolved({'id':c},b);expect(d)['toBe']('travel_shop_machine:\x20Node<WOW>\x20→\x20Node<WOW>'),expect(d)['not']['toContain']('::node::'),expect(d)['not']['toContain']('0x2::machine::Node');}),it('findingWhereResolved\x20resolves\x20R2/R7\x20object\x20addresses\x20to\x20names',()=>{const a='0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',b=graphWith([objectNode(MACHINE,'svc'),objectNode(a,'reserve_treasury')]),c=createNameResolver(buildNameIndex(b));expect(findingWhereResolved({'id':'R2:'+MACHINE},c))['toBe']('svc'),expect(findingWhereResolved({'id':'R7:treasury:'+a},c))['toBe']('Treasury\x20reserve_treasury');});});
|
|
1
|
+
import{describe,expect,it}from'vitest';import{ENTRYPOINT}from'@wowok/wowok';import{findingWhereResolved}from'./analyze.js';import{buildNameIndex,createNameResolver,humanizeStoredName,humanizeTypeTag,shortAddress}from'./names.js';const MACHINE='0x14b474d65159538031a75d37e4eb2367971fd30743df75e4472894be4f3c0e8f',TYPE_TAG_NODE='0x2::machine::Node<0x2::wow::WOW>';function graphWith(a){return{'network':ENTRYPOINT['Mainnet'],'seed':MACHINE,'builtAt':0x1,'nodes':new Map(a['map'](b=>[b['id'],b])),'edges':[],'out':new Map(),'inc':new Map(),'gaps':[],'truncations':[],'rpcReport':{'batches':0x0,'byChannel':{'objects':0x0,'keyedFields':0x0,'tables':0x0,'events':0x0},'dedupHits':0x0},'budgetExhausted':{}};}function objectNode(a,b){return{'id':a,'kind':'object','objectType':'Machine','state':'fetched','origins':[],'depth':0x0,'raw':{'object':a,'type':'Machine',...b!==undefined?{'data':{'name':b}}:{}}};}describe('humanizeTypeTag',()=>{it('shortens\x20a\x20Move\x20type\x20tag\x20to\x20its\x20struct\x20+\x20generic-param\x20last\x20segments',()=>{expect(humanizeTypeTag(TYPE_TAG_NODE))['toBe']('Node<WOW>'),expect(humanizeTypeTag('0x2::machine::Node'))['toBe']('Node');}),it('passes\x20plain\x20business\x20names\x20through\x20as\x20null',()=>{expect(humanizeTypeTag('Order\x20Confirmed'))['toBeNull'](),expect(humanizeTypeTag('paid'))['toBeNull']();}),it('keeps\x20nested\x20generics\x20depth-correct',()=>{expect(humanizeTypeTag('0x1::a::Box<0x2::b::C<0x3::d::E>,\x200x4::f::G>'))['toBe']('Box<C<E>,\x20G>');});}),describe('humanizeStoredName',()=>{it('carries\x20the\x20verbatim\x20tag\x20as\x20full\x20when\x20humanized',()=>{expect(humanizeStoredName(TYPE_TAG_NODE))['toEqual']({'label':'Node<WOW>','full':TYPE_TAG_NODE}),expect(humanizeStoredName('Order\x20Confirmed'))['toEqual']({'label':'Order\x20Confirmed'});});}),describe('buildNameIndex\x20+\x20createNameResolver',()=>{it('resolves\x20named\x20machines\x20by\x20on-chain\x20name\x20and\x20unnamed\x20to\x20a\x20short\x20address',()=>{const a='0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',b=graphWith([objectNode(MACHINE,'travel_shop_machine'),objectNode(a)]),c=createNameResolver(buildNameIndex(b));expect(c['resolve'](MACHINE)['label'])['toBe']('travel_shop_machine');const d=c['resolve'](a);expect(d['label'])['toBe'](shortAddress(a)),expect(d['label'])['toBe']('AAAA-AAA'),expect(d['full'])['toBe'](a);}),it('resolves\x20synthetic\x20wf\x20node\x20ids:\x20machine\x20name\x20+\x20humanized\x20type-tag\x20node\x20(AC-6)',()=>{const a=graphWith([objectNode(MACHINE,'travel_shop_machine')]),b=createNameResolver(buildNameIndex(a)),c=MACHINE+'::node::'+TYPE_TAG_NODE,d=b['resolveWf'](c);expect(d['machine']['label'])['toBe']('travel_shop_machine'),expect(d['node'])['toEqual']({'label':'Node<WOW>','full':TYPE_TAG_NODE}),expect(b['resolve'](c)['label'])['toContain']('Node<WOW>'),expect(b['resolve'](c)['label'])['not']['toContain']('::node::');}),it('findingWhereResolved\x20renders\x20machine\x20name\x20+\x20node\x20labels\x20in\x20R4\x20lines',()=>{const a=graphWith([objectNode(MACHINE,'travel_shop_machine')]),b=createNameResolver(buildNameIndex(a)),c='R4:'+MACHINE+':'+MACHINE+'::node::'+TYPE_TAG_NODE+'→'+MACHINE+'::node::'+TYPE_TAG_NODE,d=findingWhereResolved({'id':c},b);expect(d)['toBe']('travel_shop_machine:\x20Node<WOW>\x20→\x20Node<WOW>'),expect(d)['not']['toContain']('::node::'),expect(d)['not']['toContain']('0x2::machine::Node');}),it('findingWhereResolved\x20resolves\x20R2/R7\x20object\x20addresses\x20to\x20names',()=>{const a='0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',b=graphWith([objectNode(MACHINE,'svc'),objectNode(a,'reserve_treasury')]),c=createNameResolver(buildNameIndex(b));expect(findingWhereResolved({'id':'R2:'+MACHINE},c))['toBe']('svc'),expect(findingWhereResolved({'id':'R7:treasury:'+a},c))['toBe']('Treasury\x20reserve_treasury');});});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FindingExposure, FindingSeverity } from "./types.js";
|
|
2
|
+
import { type Facts } from "../../config/rule-engine.js";
|
|
3
|
+
export interface GraphFindingPolicy {
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
severity: FindingSeverity | null;
|
|
6
|
+
exposure?: FindingExposure;
|
|
7
|
+
}
|
|
8
|
+
export declare function graphFindingPolicy(ruleId: string, facts: Facts): GraphFindingPolicy;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{evaluateRuleBook}from'../../config/rule-engine.js';import{policyJudgmentDoc}from'../../config/judgment.js';const GRAPH_DOMAIN='graph';export function graphFindingPolicy(a,b){try{const c=policyJudgmentDoc()['rules']?.['domains']?.[GRAPH_DOMAIN]?.['rules']['find'](g=>g['rule_id']===a);if(!c)return{'enabled':!![],'severity':null};if(c['enabled']===![])return{'enabled':![],'severity':null};const {findings:d}=evaluateRuleBook([c],{'kernel_fired':!![],...b});if(d['length']===0x0)return{'enabled':!![],'severity':null};const e=d[0x0];return{'enabled':!![],'severity':e['level'],...e['exposure']?{'exposure':e['exposure']}:{}};}catch{return{'enabled':!![],'severity':null};}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{wowAddressKind}from'@wowok/wowok';import{inferObjectType}from'./extract.js';const PROJECT_TO_SDK={'service':'Service','machine':'Machine','allocation':'Allocation','treasury':'Treasury','arb':'Arb','reward':'Reward','progress':'Progress','order':'Order','permission':'Permission','guard':'Guard','contact':'Contact','repository':'Repository','demand':'Demand','payment':'Payment','proof':'Proof','resource':'Resource','registrar':'EntityRegistrar','personal':'Personal','util':'Util','bridge':'Bridge'},EXTERNAL_PROVENANCE_KEYS=new Set(['bridge']);function sdkObjectTypeOf(a){return PROJECT_TO_SDK[a['trim']()['toLowerCase']()];}export function makeProposalNode(a,b,c=[]){const d='proposal::'+a['trim']()['toLowerCase'](),e=a['trim']()['toLowerCase']();return{'id':d,'kind':'object','objectType':sdkObjectTypeOf(a),'state':'stub','raw':{'object':d,'data':b},'origins':[],'depth':0x0,'proposal':{'sourceKey':a,'missingDimensions':[...c],...EXTERNAL_PROVENANCE_KEYS['has'](e)?{'provenance':'external'}:{}}};}const MAX_WALK_DEPTH=0x8,MAX_REFS_PER_PROPOSAL=0x40,GAP_PREFIX='proposal-graph:';function toCanonicalAddress(a){const b=a['toLowerCase']()['startsWith']('0x'),c=b?a['slice'](0x2):a;if(c['length']===0x0||c['length']>0x40||!/^[0-9a-f]+$/['test'](c))return undefined;if(!b&&c['length']<0x4)return undefined;return'0x'+c['padStart'](0x40,'0');}export async function buildProposalGraph(a,b){const c=Date['now'](),d=new Map(),e=[],f=new Map(),g=new Map(),h=[],i=[],j=new Map();let k=0x0;const l=Object['keys'](a??{}),m=t=>'proposal::'+t['trim']()['toLowerCase'](),n=t=>{if(d['has'](t['id'])){k++;return;}d['set'](t['id'],t);},o=t=>{f['set'](t['from'],[...f['get'](t['from'])??[],t]),g['set'](t['to'],[...g['get'](t['to'])??[],t]),e['push'](t);};for(const t of l){const u=a[t];n(makeProposalNode(t,u?.['puzzle'],u?.['missing_dimensions']??[]));}const p=new Set(l['map'](v=>v['trim']()['toLowerCase']())),q=(v,w)=>{const x=[];let y=![];const z=new WeakSet(),A=(B,C,D)=>{if(x['length']>=MAX_REFS_PER_PROPOSAL){!y&&(y=!![],h['push'](GAP_PREFIX+'\x20fanout\x20cap\x20('+MAX_REFS_PER_PROPOSAL+')\x20reached\x20at\x20'+v+'\x20—\x20remaining\x20references\x20skipped'),i['push']({'nodeId':v,'schema':'proposal.*','observed':MAX_REFS_PER_PROPOSAL,'limit':MAX_REFS_PER_PROPOSAL,'reason':'fanout'}));return;}if(D>MAX_WALK_DEPTH||B==null||B==='')return;if(typeof B==='string'){const E=B['trim']();if(!E)return;if(p['has'](E['toLowerCase']())&&m(E)!==v){x['push']({'fieldPath':C,'target':E,'kind':'proposal'});return;}const F=toCanonicalAddress(E);if(!F)return;x['push']({'fieldPath':C,'target':F,'kind':wowAddressKind(F)==='user'?'eoa':'object'});return;}if(typeof B!=='object')return;if(z['has'](B))return;z['add'](B);if(Array['isArray'](B))B['forEach']((G,H)=>A(G,C+'.'+H,D+0x1));else for(const [G,H]of Object['entries'](B)){A(H,C?C+'.'+G:G,D+0x1);}};return A(w,'',0x0),x;};for(const v of l){const w=m(v),x=q(w,a[v]?.['puzzle']);if(x['length']===0x0)continue;j['set'](w,x);for(const y of x){const z=y['kind']==='proposal'?m(y['target']):y['target'];n({'id':z,'kind':y['kind']==='eoa'?'eoa':'object',...y['kind']==='object'?{'objectType':inferObjectType(y['target'])}:{},'state':'stub','origins':[{'via':'proposal.'+y['fieldPath'],'from':w,'depth':0x1}],'depth':0x1}),o({'id':'proposal.'+y['fieldPath']+'|'+w+'→'+z,'schema':'proposal.'+y['fieldPath'],'family':'F','from':w,'to':z,'retention':'derived','
|
|
1
|
+
import{wowAddressKind}from'@wowok/wowok';import{inferObjectType}from'./extract.js';const PROJECT_TO_SDK={'service':'Service','machine':'Machine','allocation':'Allocation','treasury':'Treasury','arb':'Arb','reward':'Reward','progress':'Progress','order':'Order','permission':'Permission','guard':'Guard','contact':'Contact','repository':'Repository','demand':'Demand','payment':'Payment','proof':'Proof','resource':'Resource','registrar':'EntityRegistrar','personal':'Personal','util':'Util','bridge':'Bridge'},EXTERNAL_PROVENANCE_KEYS=new Set(['bridge']);function sdkObjectTypeOf(a){return PROJECT_TO_SDK[a['trim']()['toLowerCase']()];}export function makeProposalNode(a,b,c=[]){const d='proposal::'+a['trim']()['toLowerCase'](),e=a['trim']()['toLowerCase']();return{'id':d,'kind':'object','objectType':sdkObjectTypeOf(a),'state':'stub','raw':{'object':d,'data':b},'origins':[],'depth':0x0,'proposal':{'sourceKey':a,'missingDimensions':[...c],...EXTERNAL_PROVENANCE_KEYS['has'](e)?{'provenance':'external'}:{}}};}const MAX_WALK_DEPTH=0x8,MAX_REFS_PER_PROPOSAL=0x40,GAP_PREFIX='proposal-graph:';function toCanonicalAddress(a){const b=a['toLowerCase']()['startsWith']('0x'),c=b?a['slice'](0x2):a;if(c['length']===0x0||c['length']>0x40||!/^[0-9a-f]+$/['test'](c))return undefined;if(!b&&c['length']<0x4)return undefined;return'0x'+c['padStart'](0x40,'0');}export async function buildProposalGraph(a,b){const c=Date['now'](),d=new Map(),e=[],f=new Map(),g=new Map(),h=[],i=[],j=new Map();let k=0x0;const l=Object['keys'](a??{}),m=t=>'proposal::'+t['trim']()['toLowerCase'](),n=t=>{if(d['has'](t['id'])){k++;return;}d['set'](t['id'],t);},o=t=>{f['set'](t['from'],[...f['get'](t['from'])??[],t]),g['set'](t['to'],[...g['get'](t['to'])??[],t]),e['push'](t);};for(const t of l){const u=a[t];n(makeProposalNode(t,u?.['puzzle'],u?.['missing_dimensions']??[]));}const p=new Set(l['map'](v=>v['trim']()['toLowerCase']())),q=(v,w)=>{const x=[];let y=![];const z=new WeakSet(),A=(B,C,D)=>{if(x['length']>=MAX_REFS_PER_PROPOSAL){!y&&(y=!![],h['push'](GAP_PREFIX+'\x20fanout\x20cap\x20('+MAX_REFS_PER_PROPOSAL+')\x20reached\x20at\x20'+v+'\x20—\x20remaining\x20references\x20skipped'),i['push']({'nodeId':v,'schema':'proposal.*','observed':MAX_REFS_PER_PROPOSAL,'limit':MAX_REFS_PER_PROPOSAL,'reason':'fanout'}));return;}if(D>MAX_WALK_DEPTH||B==null||B==='')return;if(typeof B==='string'){const E=B['trim']();if(!E)return;if(p['has'](E['toLowerCase']())&&m(E)!==v){x['push']({'fieldPath':C,'target':E,'kind':'proposal'});return;}const F=toCanonicalAddress(E);if(!F)return;x['push']({'fieldPath':C,'target':F,'kind':wowAddressKind(F)==='user'?'eoa':'object'});return;}if(typeof B!=='object')return;if(z['has'](B))return;z['add'](B);if(Array['isArray'](B))B['forEach']((G,H)=>A(G,C+'.'+H,D+0x1));else for(const [G,H]of Object['entries'](B)){A(H,C?C+'.'+G:G,D+0x1);}};return A(w,'',0x0),x;};for(const v of l){const w=m(v),x=q(w,a[v]?.['puzzle']);if(x['length']===0x0)continue;j['set'](w,x);for(const y of x){const z=y['kind']==='proposal'?m(y['target']):y['target'];n({'id':z,'kind':y['kind']==='eoa'?'eoa':'object',...y['kind']==='object'?{'objectType':inferObjectType(y['target'])}:{},'state':'stub','origins':[{'via':'proposal.'+y['fieldPath'],'from':w,'depth':0x1}],'depth':0x1}),o({'id':'proposal.'+y['fieldPath']+'|'+w+'→'+z,'schema':'proposal.'+y['fieldPath'],'family':'F','from':w,'to':z,'retention':'derived','observedAt':c,'payload':{'fieldPath':y['fieldPath']}});}}const r=[...new Set([...j['values']()]['flatMap'](A=>A['filter'](B=>B['kind']==='object')['map'](B=>B['target'])))];if(b['plane']&&r['length']>0x0){const A=await b['plane']['getObjects'](r);for(const B of r){const C=d['get'](B);if(!C)continue;const D=A['get'](B);if(D){C['state']='fetched',C['raw']=D;if(D['type'])C['objectType']=String(D['type']);}else h['push'](GAP_PREFIX+'\x20unresolved\x20object\x20reference\x20'+B+'\x20—\x20stays\x20a\x20stub');}}else!b['plane']&&r['length']>0x0&&h['push'](GAP_PREFIX+'\x20no\x20DataPlane\x20—\x20'+r['length']+'\x20object\x20reference(s)\x20stay\x20stubs');const s=(b['seed']??[...d['values']()]['filter'](E=>E['proposal'])['map'](E=>E['id'])['sort']()[0x0]??'')['toLowerCase']();return{'network':b['network'],'seed':s,'builtAt':c,'nodes':d,'edges':e,'out':f,'inc':g,'gaps':h,'truncations':i,'rpcReport':{'batches':b['plane']&&r['length']>0x0?0x1:0x0,'byChannel':{'objects':b['plane']?r['length']:0x0,'keyedFields':0x0,'tables':0x0,'events':0x0},'dedupHits':k},'budgetExhausted':{}};}const MAX_PROPOSAL_FINDINGS=0x14;export const PROPOSAL_GAP_ANALYZER={'id':'proposal.gap','kind':'risk','run'(a){const b=[];for(const c of a['visibleNodes']){if(b['length']>=MAX_PROPOSAL_FINDINGS)break;const d=a['graph']['nodes']['get'](c),e=d?.['proposal'];if(!e||e['missingDimensions']['length']===0x0)continue;b['push']({'id':'proposal.gap:'+d['id'],'kind':'risk','severity':'info','title':'Proposal\x20\x27'+e['sourceKey']+'\x27\x20is\x20missing\x20puzzle\x20dimensions','path':[d['id']],'confidence':'exact','roles':['neutral','merchant'],'detail':'Business\x20puzzle\x20for\x20\x27'+e['sourceKey']+'\x27\x20still\x20misses:\x20'+e['missingDimensions']['join'](',\x20')+'.','suggestion':'Complete\x20the\x20missing\x20dimensions\x20of\x20\x27'+e['sourceKey']+'\x27\x20before\x20publishing.','source':'proposal'});}return b;}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{describe,it,expect}from'vitest';import{ENTRYPOINT}from'@wowok/wowok';import{buildProposalGraph,buildViewport,runAnalyzers,listAnalyzers,FakeDataPlane}from'./index.js';import{RISK_CASES}from'../../knowledge/baselines/risk-cases.js';import{analyzeBusinessIntent}from'../../playbooks/service-build/business-puzzle.js';const EOA='0x'+'00'['repeat'](0x20),MACHINE='0x'+'15'+'ab'['repeat'](0x1f),SERVICE_ONCHAIN='0x'+'14'+'cd'['repeat'](0x1f),entry=(a,b=[])=>({'puzzle':a,'completeness':{},'missing_dimensions':b}),SNAPSHOT={'service':entry({'binding':{'permission':'Permission','machine':MACHINE,'arbitrations':[],'buy_guard':null,'um':''},'owner_note':'plain\x20prose,\x20never\x20an\x20address','admin':EOA,'upgrade_to':SERVICE_ONCHAIN},['Pricing','Arbitration']),'permission':entry({'threshold':0x2,'note':'co-sign'})};async function build(a,b){return buildProposalGraph(a,{'network':ENTRYPOINT['Testnet'],...b?{'plane':b['plane']}:{}});}describe('buildProposalGraph\x20(T22)',()=>{it('TR-22.1\x20synthesizes\x20one\x20proposal\x20node\x20per\x20snapshot\x20key',async()=>{const a=await build(SNAPSHOT);expect(a['nodes']['size'])['toBe'](0x2+0x3),expect(a['nodes']['get']('proposal::service')?.['proposal'])['toEqual']({'sourceKey':'service','missingDimensions':['Pricing','Arbitration']}),expect(a['nodes']['get']('proposal::permission')?.['proposal']?.['missingDimensions'])['toEqual']([]),expect(a['nodes']['get']('proposal::service')?.['objectType'])['toBe']('Service'),expect(a['nodes']['get']('proposal::permission')?.['objectType'])['toBe']('Permission');const b=a['nodes']['get']('proposal::service');expect(b['state'])['toBe']('stub'),expect(b['kind'])['toBe']('object'),expect((b['raw']?.['data'])['binding'])['toBeDefined'](),expect(b['depth'])['toBe'](0x0);}),it('TR-22.1\x20edges\x20mirror\x20declared\x20references\x20with\x20proposal.*\x20schemas',async()=>{const a=await build(SNAPSHOT);expect(a['edges']['length'])['toBe'](0x4);const b=a['edges']['map'](d=>d['schema'])['sort']();expect(b)['toEqual'](['proposal.admin','proposal.binding.machine','proposal.binding.permission','proposal.upgrade_to']);for(const d of a['edges']){expect(d['family'])['toBe']('F'),expect(d['retention'])['toBe']('derived'),expect(d['
|
|
1
|
+
import{describe,it,expect}from'vitest';import{ENTRYPOINT}from'@wowok/wowok';import{buildProposalGraph,buildViewport,runAnalyzers,listAnalyzers,FakeDataPlane}from'./index.js';import{RISK_CASES}from'../../knowledge/baselines/risk-cases.js';import{analyzeBusinessIntent}from'../../playbooks/service-build/business-puzzle.js';const EOA='0x'+'00'['repeat'](0x20),MACHINE='0x'+'15'+'ab'['repeat'](0x1f),SERVICE_ONCHAIN='0x'+'14'+'cd'['repeat'](0x1f),entry=(a,b=[])=>({'puzzle':a,'completeness':{},'missing_dimensions':b}),SNAPSHOT={'service':entry({'binding':{'permission':'Permission','machine':MACHINE,'arbitrations':[],'buy_guard':null,'um':''},'owner_note':'plain\x20prose,\x20never\x20an\x20address','admin':EOA,'upgrade_to':SERVICE_ONCHAIN},['Pricing','Arbitration']),'permission':entry({'threshold':0x2,'note':'co-sign'})};async function build(a,b){return buildProposalGraph(a,{'network':ENTRYPOINT['Testnet'],...b?{'plane':b['plane']}:{}});}describe('buildProposalGraph\x20(T22)',()=>{it('TR-22.1\x20synthesizes\x20one\x20proposal\x20node\x20per\x20snapshot\x20key',async()=>{const a=await build(SNAPSHOT);expect(a['nodes']['size'])['toBe'](0x2+0x3),expect(a['nodes']['get']('proposal::service')?.['proposal'])['toEqual']({'sourceKey':'service','missingDimensions':['Pricing','Arbitration']}),expect(a['nodes']['get']('proposal::permission')?.['proposal']?.['missingDimensions'])['toEqual']([]),expect(a['nodes']['get']('proposal::service')?.['objectType'])['toBe']('Service'),expect(a['nodes']['get']('proposal::permission')?.['objectType'])['toBe']('Permission');const b=a['nodes']['get']('proposal::service');expect(b['state'])['toBe']('stub'),expect(b['kind'])['toBe']('object'),expect((b['raw']?.['data'])['binding'])['toBeDefined'](),expect(b['depth'])['toBe'](0x0);}),it('TR-22.1\x20edges\x20mirror\x20declared\x20references\x20with\x20proposal.*\x20schemas',async()=>{const a=await build(SNAPSHOT);expect(a['edges']['length'])['toBe'](0x4);const b=a['edges']['map'](d=>d['schema'])['sort']();expect(b)['toEqual'](['proposal.admin','proposal.binding.machine','proposal.binding.permission','proposal.upgrade_to']);for(const d of a['edges']){expect(d['family'])['toBe']('F'),expect(d['retention'])['toBe']('derived'),expect(d['from'])['toBe']('proposal::service'),expect(d['payload']?.['fieldPath'])['toBe'](d['schema']['slice']('proposal.'['length']));}expect(a['nodes']['get'](MACHINE)?.['kind'])['toBe']('object'),expect(a['nodes']['get'](MACHINE)?.['objectType'])['toBe']('Machine'),expect(a['nodes']['get'](SERVICE_ONCHAIN)?.['objectType'])['toBe']('Service'),expect(a['nodes']['get'](EOA)?.['kind'])['toBe']('eoa'),expect(a['nodes']['get'](MACHINE)?.['depth'])['toBe'](0x1),expect(a['nodes']['get'](MACHINE)?.['origins'][0x0]?.['via'])['toBe']('proposal.binding.machine');const c=a['edges']['find'](f=>f['schema']==='proposal.binding.permission');expect(c['to'])['toBe']('proposal::permission');}),it('TR-22.1\x20missing\x20dimensions\x20produce\x20proposal-gap\x20findings,\x20never\x20throws',async()=>{const a=await build(SNAPSHOT),b=buildViewport(a,EOA,'neutral'),c=runAnalyzers(b),d=c['filter'](e=>e['id']['startsWith']('proposal.gap'));expect(d['length'])['toBe'](0x1),expect(d[0x0]['source'])['toBe']('proposal'),expect(d[0x0]['severity'])['toBe']('info'),expect(d[0x0]['detail'])['toContain']('Pricing'),expect(d[0x0]['detail'])['toContain']('Arbitration'),expect(d[0x0]['path'])['toEqual'](['proposal::service']);}),it('whole\x20analysis\x20stack\x20runs\x20unmodified;\x20no\x20on-chain\x20analyzer\x20misfires',async()=>{const a=await build(SNAPSHOT),b=buildViewport(a,EOA,'neutral');expect(b['visibleNodes']['size'])['toBe'](a['nodes']['size']),expect(b['visibleEdges']['length'])['toBe'](a['edges']['length']);const c=runAnalyzers(b);for(const e of c)expect(e['id']['startsWith']('proposal.gap'))['toBe'](!![]);expect(listAnalyzers())['toContain']('proposal.gap');const d=buildViewport(a,'proposal::service','merchant');expect(d['visibleNodes']['size'])['toBe'](a['nodes']['size']),expect(d['visibleEdges']['length'])['toBe'](a['edges']['length']);}),it('no\x20DataPlane:\x20chain\x20refs\x20stay\x20stubs\x20with\x20a\x20gap\x20line',async()=>{const a=await build(SNAPSHOT);expect(a['nodes']['get'](MACHINE)?.['state'])['toBe']('stub'),expect(a['gaps']['some'](b=>b['includes']('no\x20DataPlane')))['toBe'](!![]),expect(a['rpcReport']['batches'])['toBe'](0x0);}),it('FakeDataPlane\x20enriches\x20known\x20refs,\x20unknown\x20refs\x20degrade\x20to\x20stub\x20+\x20gap',async()=>{const a=new FakeDataPlane({'objects':new Map([[MACHINE,{'object':MACHINE,'type':'Machine','data':{'pairs':[]}}]])}),b=await build(SNAPSHOT,{'plane':a}),c=b['nodes']['get'](MACHINE);expect(c['state'])['toBe']('fetched'),expect(c['raw']?.['type'])['toBe']('Machine'),expect(c['objectType'])['toBe']('Machine'),expect(b['nodes']['get'](SERVICE_ONCHAIN)?.['state'])['toBe']('stub'),expect(b['gaps']['some'](d=>d['includes']('unresolved\x20object\x20reference')))['toBe'](!![]),expect(b['rpcReport']['batches'])['toBe'](0x1);}),it('real\x20analyzeBusinessIntent\x20snapshot\x20builds\x20consistently\x20(Task\x202\x20baseline)',async()=>{const a=analyzeBusinessIntent({'user_intent':'I\x20want\x20to\x20sell\x20products\x20in\x20an\x20online\x20store\x20with\x20arbitration\x20protection'}),b=a['puzzles'];expect(Object['keys'](b)['length'])['toBeGreaterThan'](0x0);const c=await build(b),d=[...c['nodes']['values']()]['filter'](h=>h['proposal']);expect(d['length'])['toBe'](Object['keys'](b)['length']);for(const h of c['edges']){expect(h['from']['startsWith']('proposal::'))['toBe'](!![]),expect(c['nodes']['has'](h['to']))['toBe'](!![]);}const f=runAnalyzers(buildViewport(c,EOA,'neutral'));expect(Array['isArray'](f))['toBe'](!![]);}),it('RISK_CASES\x20baseline\x20contexts\x20build\x20without\x20throwing\x20(all\x2021\x20packs)',async()=>{const a=new Set(RISK_CASES['map'](g=>g['objectType'])),b={};for(const g of RISK_CASES)b[g['objectType']]=entry(g['empty']);const d=await build(b);expect(d['nodes']['size'])['toBe'](a['size']),expect(d['edges']['length'])['toBe'](0x0);const e={};for(const h of RISK_CASES)e[h['objectType']]=entry(h['trigger']);const f=await build(e);expect(f['nodes']['size'])['toBe'](a['size']+0x41),expect(f['truncations'])['toEqual']([{'nodeId':'proposal::reward','schema':'proposal.*','observed':0x40,'limit':0x40,'reason':'fanout'}]),expect(f['edges']['filter'](i=>i['from']==='proposal::reward')['length'])['toBe'](0x40);}),it('cycle-safe:\x20self-referencing\x20puzzle\x20payloads\x20terminate',async()=>{const a={'name':'a'};a['self']=a;const b={'tag':'x'};b['back']=b;const c=await build({'service':entry({'loop':a,'shared':b})});expect(c['nodes']['has']('proposal::service'))['toBe'](!![]),expect(c['edges']['length'])['toBe'](0x0);}),it('fanout\x20cap:\x20>64\x20references\x20truncate\x20with\x20an\x20explicit\x20record',async()=>{const a={'guards':Array['from']({'length':0x50},(d,e)=>'0x'+(e+0x1)['toString'](0x10)['padStart'](0x40,'0'))},b=await build({'machine':entry(a)}),c=b['edges']['filter'](d=>d['from']==='proposal::machine');expect(c['length'])['toBe'](0x40),expect(b['truncations']['length'])['toBe'](0x1),expect(b['truncations'][0x0]['reason'])['toBe']('fanout'),expect(b['gaps']['some'](d=>d['includes']('fanout\x20cap')))['toBe'](!![]);}),it('seed\x20defaults\x20to\x20the\x20first\x20proposal\x20node;\x20shorthand\x20hex\x20pads\x20left\x20(chain\x20convention)',async()=>{const a=await build(SNAPSHOT);expect(a['seed'])['toBe']('proposal::permission');const b=await build({'service':entry({'fee_receiver':'0x15'})}),c=[...b['nodes']['values']()]['find'](d=>d['id']['startsWith']('0x'));expect(c?.['id'])['toBe']('0x'+'15'['padStart'](0x40,'0')),expect(c?.['kind'])['toBe']('eoa');});});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Severity } from "../../config/severity.js";
|
|
2
|
+
import type { Finding } from "./types.js";
|
|
3
|
+
import type { OpenQuestion } from "./exploration.js";
|
|
4
|
+
export type SynthesisPosture = "prefer" | "avoid" | "neutral";
|
|
5
|
+
export interface RoleVerdict {
|
|
6
|
+
role: string;
|
|
7
|
+
level: Severity;
|
|
8
|
+
drivers: string[];
|
|
9
|
+
open_questions: string[];
|
|
10
|
+
posture: SynthesisPosture;
|
|
11
|
+
}
|
|
12
|
+
export interface SynthesisBlock {
|
|
13
|
+
per_role: RoleVerdict[];
|
|
14
|
+
basis: string;
|
|
15
|
+
}
|
|
16
|
+
export interface SynthesisInput {
|
|
17
|
+
findings: ReadonlyArray<Finding>;
|
|
18
|
+
openQuestions?: ReadonlyArray<OpenQuestion>;
|
|
19
|
+
}
|
|
20
|
+
export declare function synthesizeVerdicts(input: SynthesisInput): SynthesisBlock | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{EXPOSURE_ROLES}from'../../config/exposure.js';import{maxSeverity}from'../../config/severity.js';import{policyJudgmentDoc}from'../../config/judgment.js';import{toCommercialRole}from'./interest.js';function drives(a,b){const c=a['exposure'];if(!c)return![];if(c['lossParties']['some'](d=>d['role']===b))return!![];return c['gainPaths']['some'](d=>d['role']===b&&(d['viability']==='viable'||d['viability']==='conditional'));}function postureFor(a,b){const c=policyJudgmentDoc()['game']?.['role_interests']?.[toCommercialRole(a)];if(!c)return'neutral';const d=b['toLowerCase']();if(c['avoid']['some'](e=>d['includes'](e['toLowerCase']())))return'avoid';if(c['prefer']['some'](e=>d['includes'](e['toLowerCase']())))return'prefer';return'neutral';}export function synthesizeVerdicts(a){const {findings:b,openQuestions:openQuestions=[]}=a,c=[];for(const f of EXPOSURE_ROLES){const g=b['filter'](l=>drives(l,f));if(g['length']===0x0)continue;const h=g['map'](l=>l['id']),i=maxSeverity(g['map'](l=>l['severity'])),j=openQuestions['filter'](l=>h['includes'](l['source']))['map'](l=>l['id']),k=g['map'](l=>l['title']+'\x20'+l['detail'])['join']('\x20');c['push']({'role':f,'level':i,'drivers':h,'open_questions':j,'posture':postureFor(f,k)});}if(c['length']===0x0)return undefined;const d=c['reduce']((l,m)=>l+m['open_questions']['length'],0x0),e='Per-role\x20verdicts\x20=\x20max\x20severity\x20over\x20exposure-driver\x20findings\x20(loss\x20parties\x20plus\x20viable/conditional\x20gain-path\x20roles);\x20'+'posture\x20from\x20the\x20judgment\x20game.role_interests\x20prefer/avoid\x20keyword\x20table\x20over\x20driver\x20texts;\x20'+(d+'\x20exploration\x20lead(s)\x20remain\x20open\x20across\x20these\x20verdicts.\x20')+'Provisional\x20by\x20construction\x20—\x20a\x20verdict\x20never\x20closes\x20while\x20its\x20open\x20questions\x20stand.';return{'per_role':c,'basis':e};}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{mkdtempSync,writeFileSync}from'node:fs';import{tmpdir}from'node:os';import{join}from'node:path';import{beforeAll,describe,expect,it}from'vitest';import{beginPolicyRun,endPolicyRun}from'../../config/judgment.js';import{synthesizeVerdicts}from'./synthesis.js';const CONFIG_DIR=mkdtempSync(join(tmpdir(),'wowok-synthesis-'));process['env']['WOWOK_CONFIG_DIR']=CONFIG_DIR,beforeAll(()=>{writeFileSync(join(CONFIG_DIR,'judgment.json'),JSON['stringify']({'version':0x1,'game':{'role_interests':{'customer':{'prefer':['refund'],'avoid':['theft','steal'],'sensitivity':0x1},'merchant':{'prefer':['throughput'],'avoid':[],'sensitivity':0x1}}}}),'utf-8'),beginPolicyRun(),endPolicyRun(),beginPolicyRun();});function finding(a){return{'id':'F1','kind':'risk','severity':'high','title':'t','path':[],'confidence':'exact','roles':['buyer'],'detail':'d','suggestion':'s',...a};}describe('synthesizeVerdicts\x20—\x20drivers\x20and\x20aggregation',()=>{it('returns\x20undefined\x20when\x20no\x20finding\x20carries\x20exposure',()=>{expect(synthesizeVerdicts({'findings':[]}))['toBeUndefined'](),expect(synthesizeVerdicts({'findings':[finding({})]}))['toBeUndefined']();const a=finding({'exposure':{'lossParties':[],'gainPaths':[{'role':'neutral','path':'p','viability':'blocked','gate':'g'}],'verdict':'downgraded','baseSeverity':'high'}});expect(synthesizeVerdicts({'findings':[a]}))['toBeUndefined']();}),it('a\x20role\x20is\x20driven\x20by\x20loss\x20parties\x20and\x20viable/conditional\x20gain\x20paths\x20only',()=>{const a=finding({'id':'F1','severity':'high','exposure':{'lossParties':[{'role':'buyer','basis':'b'}],'gainPaths':[{'role':'merchant','path':'viable\x20path','viability':'viable','gate':'g'},{'role':'supplier','path':'conditional\x20path','viability':'conditional','gate':'g'},{'role':'neutral','path':'unverifiable\x20path','viability':'unverifiable','gate':'g'},{'role':'arbitrator','path':'blocked\x20path','viability':'blocked','gate':'g'}],'verdict':'confirmed'}}),b=synthesizeVerdicts({'findings':[a]});expect(b)['toBeDefined']();const c=b['per_role']['map'](d=>d['role'])['sort']();expect(c)['toEqual'](['buyer','merchant','supplier']),expect(b['per_role']['every'](d=>d['level']==='high'))['toBe'](!![]),expect(b['per_role']['every'](d=>d['drivers']['length']===0x1))['toBe'](!![]);}),it('level\x20is\x20the\x20max\x20driver\x20severity;\x20every\x20driver\x20id\x20is\x20carried',()=>{const a=finding({'id':'F-low','severity':'low','exposure':{'lossParties':[{'role':'buyer','basis':'b'}],'gainPaths':[],'verdict':'confirmed'}}),b=finding({'id':'F-critical','severity':'critical','exposure':{'lossParties':[{'role':'buyer','basis':'b'}],'gainPaths':[],'verdict':'confirmed'}}),c=synthesizeVerdicts({'findings':[a,b]}),d=c['per_role']['find'](e=>e['role']==='buyer');expect(d['level'])['toBe']('critical'),expect(d['drivers']['sort']())['toEqual'](['F-critical','F-low']);});}),describe('synthesizeVerdicts\x20—\x20posture\x20and\x20open\x20questions',()=>{it('posture\x20hits\x20the\x20injected\x20game.role_interests\x20keywords\x20over\x20driver\x20texts',()=>{const a=finding({'id':'F-theft','title':'Fund\x20theft\x20risk:\x20Signer\x20recipient\x20without\x20caller\x20identity\x20constraint','detail':'anyone\x20can\x20take\x20the\x20funds','exposure':{'lossParties':[{'role':'buyer','basis':'b'}],'gainPaths':[],'verdict':'confirmed'}}),b=finding({'id':'F-flow','title':'Steady\x20settlement\x20throughput\x20on\x20the\x20allocation\x20route','detail':'allocations\x20settle\x20on\x20schedule','exposure':{'lossParties':[{'role':'merchant','basis':'b'}],'gainPaths':[],'verdict':'confirmed'}}),c=synthesizeVerdicts({'findings':[a,b]});expect(c['per_role']['find'](d=>d['role']==='buyer')?.['posture'])['toBe']('avoid'),expect(c['per_role']['find'](d=>d['role']==='merchant')?.['posture'])['toBe']('prefer');}),it('a\x20role\x20without\x20interest-table\x20keywords\x20lands\x20neutral',()=>{const a=finding({'exposure':{'lossParties':[{'role':'supplier','basis':'b'}],'gainPaths':[],'verdict':'confirmed'}});expect(synthesizeVerdicts({'findings':[a]})['per_role'][0x0]['posture'])['toBe']('neutral');}),it('carries\x20only\x20the\x20open\x20questions\x20whose\x20source\x20finding\x20drives\x20the\x20role',()=>{const a=finding({'id':'F-driver','exposure':{'lossParties':[{'role':'buyer','basis':'b'}],'gainPaths':[],'verdict':'confirmed'}}),b=finding({'id':'F-other','exposure':{'lossParties':[{'role':'merchant','basis':'b'}],'gainPaths':[],'verdict':'confirmed'}}),c=[{'id':'X1','kind':'verification','question':'q1','resolves_with':[],'source':'F-driver'},{'id':'X2','kind':'data_gap','question':'q2','resolves_with':[],'source':'F-other'}],d=synthesizeVerdicts({'findings':[a,b],'openQuestions':c});expect(d['per_role']['find'](e=>e['role']==='buyer')?.['open_questions'])['toEqual'](['X1']),expect(d['per_role']['find'](e=>e['role']==='merchant')?.['open_questions'])['toEqual'](['X2']),expect(d['basis'])['toContain']('2\x20exploration\x20lead(s)\x20remain\x20open');});});
|
|
@@ -88,7 +88,6 @@ export interface TopoEdge {
|
|
|
88
88
|
from: string;
|
|
89
89
|
to: string;
|
|
90
90
|
retention: Retention;
|
|
91
|
-
evidence: string;
|
|
92
91
|
observedAt: number;
|
|
93
92
|
payload?: TopoEdgePayload;
|
|
94
93
|
truncated?: boolean;
|
|
@@ -202,6 +201,14 @@ export interface Viewport {
|
|
|
202
201
|
export type FindingKind = "risk" | "arbitrage" | "opportunity" | "game";
|
|
203
202
|
export type FindingSeverity = "info" | "low" | "medium" | "high" | "critical";
|
|
204
203
|
export type Confidence = "exact" | "bounded" | "windowed" | "derived";
|
|
204
|
+
export interface FindingAmount {
|
|
205
|
+
key: string;
|
|
206
|
+
label: string;
|
|
207
|
+
raw: string;
|
|
208
|
+
coin_type?: string;
|
|
209
|
+
}
|
|
210
|
+
import type { FindingExposure } from "../../config/exposure.js";
|
|
211
|
+
export type { ExposureParty, ExposureVerdict, FindingExposure, GainPath, GainPathViability, } from "../../config/exposure.js";
|
|
205
212
|
export interface Finding {
|
|
206
213
|
id: string;
|
|
207
214
|
kind: FindingKind;
|
|
@@ -219,8 +226,11 @@ export interface Finding {
|
|
|
219
226
|
ruleId?: string;
|
|
220
227
|
source?: "onchain" | "proposal" | "external";
|
|
221
228
|
interest?: InterestPayload;
|
|
229
|
+
amounts?: FindingAmount[];
|
|
230
|
+
objects?: string[];
|
|
222
231
|
evidence?: string;
|
|
223
232
|
nativeRisk?: unknown;
|
|
233
|
+
exposure?: FindingExposure;
|
|
224
234
|
}
|
|
225
235
|
export interface InterestStake {
|
|
226
236
|
object: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{describe,expect,it}from'vitest';import{KeeperStore}from'./KeeperStore.js';import{detectPaymentUnclaimed,detectProgressActionable}from'./detectors.js';import{executeKeeperTask,runKeeperScan}from'./KeeperScan.js';import{clampKeeperConfig,defaultKeeperConfig,KEEPER_MIN}from'./types.js';const NET='testnet',ACCT='0xaaa111',OTHER='0xbbb222';function memStorage(){const a=new Map();return{'get':async b=>a['get'](b),'put':async(b,c)=>void a['set'](b,c)};}function makeStore(){return new KeeperStore(memStorage());}function paymentItem(a,b,c=0x1){return{'dedupe_key':'payment_unclaimed:'+a,'detector':'payment_unclaimed','beneficiary':a,'operation':{'operation_type':'payment','data':{'receive':!![]}},'title':'Unclaimed\x20funds\x20—\x20'+b+'\x20waiting','state_fingerprint':c+':'+b['toString']()};}function makeScope(a){return{'version':0x1,'resolved_at':0x0,'accounts':[ACCT],'permissions':[],'managed_objects':[],'services':[],'orders':[],'order_children':[],'focus':[],'index':{},...a};}describe('keeper\x20config',()=>{it('returns\x20safe\x20defaults:\x20reminders\x20ON,\x20auto\x20rules\x20none',async()=>{const a=makeStore(),b=await a['getConfig'](NET);expect(b['enabled'])['toBe'](!![]),expect(b['detectors']['payment_unclaimed'])['toBe'](!![]),expect(b['detectors']['progress_actionable'])['toBe'](!![]),expect(await a['listRules'](NET))['toEqual']([]);}),it('config_set\x20patch\x20merges\x20detectors\x20individually',async()=>{const a=makeStore(),b=await a['saveConfig'](NET,{'detectors':{'payment_unclaimed':![]}});expect(b['detectors']['payment_unclaimed'])['toBe'](![]),expect(b['detectors']['progress_actionable'])['toBe'](!![]);const c=await a['getConfig'](NET);expect(c['detectors']['payment_unclaimed'])['toBe'](![]),expect(c['detectors']['progress_actionable'])['toBe'](!![]);}),it('clamps\x20numeric\x20bounds\x20(cost/gas\x20guards)',()=>{const a=clampKeeperConfig({...defaultKeeperConfig(),'scan_interval_ms':0x1,'max_scan_objects':0x0,'max_auto_execute_per_scan':0x0,'auto_retry_cooldown_ms':0x0});expect(a['scan_interval_ms'])['toBe'](KEEPER_MIN['scan_interval_ms']),expect(a['max_scan_objects'])['toBe'](KEEPER_MIN['max_scan_objects']),expect(a['max_auto_execute_per_scan'])['toBe'](KEEPER_MIN['max_auto_execute_per_scan']),expect(a['auto_retry_cooldown_ms'])['toBe'](KEEPER_MIN['auto_retry_cooldown_ms']);});}),describe('keeper\x20rules',()=>{const a=b=>({'id':'krule_1','enabled':!![],'detector':'payment_unclaimed','accounts':[],'auto_execute':!![],'created_at':0x0,...b});it('matchingAutoRules\x20honors\x20enabled\x20/\x20auto_execute\x20/\x20account\x20coverage',async()=>{const b=makeStore();await b['upsertRule'](NET,a()),expect(await b['matchingAutoRules'](NET,'payment_unclaimed',ACCT))['toHaveLength'](0x1),expect(await b['matchingAutoRules'](NET,'progress_actionable',ACCT))['toHaveLength'](0x0),await b['upsertRule'](NET,a({'id':'krule_2','accounts':[OTHER['toUpperCase']()]})),expect(await b['matchingAutoRules'](NET,'payment_unclaimed',ACCT))['toHaveLength'](0x1),expect(await b['matchingAutoRules'](NET,'payment_unclaimed',OTHER))['toHaveLength'](0x2),await b['upsertRule'](NET,a({'id':'krule_3','enabled':![]})),await b['upsertRule'](NET,a({'id':'krule_4','auto_execute':![]}));const c=await b['matchingAutoRules'](NET,'payment_unclaimed',OTHER);expect(c['map'](d=>d['id'])['sort']())['toEqual'](['krule_1','krule_2']);});}),describe('KeeperStore.upsertDesired',()=>{it('opens\x20new\x20tasks,\x20refreshes\x20on\x20fingerprint\x20change,\x20no\x20churn\x20when\x20identical',async()=>{const a=makeStore();let b=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);expect(b)['toEqual']({'opened':0x1,'refreshed':0x0,'revived':0x0,'superseded':0x0}),b=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x7d0),expect(b)['toEqual']({'opened':0x0,'refreshed':0x0,'revived':0x0,'superseded':0x0}),b=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0xfan)],0xbb8),expect(b)['toEqual']({'opened':0x0,'refreshed':0x1,'revived':0x0,'superseded':0x0});const c=(await a['listTasks'](NET))[0x0];expect(c['title'])['toContain']('250'),expect(c['updated_at'])['toBe'](0xbb8);}),it('dismissed\x20stays\x20dismissed\x20for\x20identical\x20state,\x20revives\x20on\x20material\x20change',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);const b=(await a['listTasks'](NET))[0x0];await a['resolveTask'](NET,b['id'],'dismissed',0x5dc,'not\x20now');let c=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x7d0);expect(c['revived'])['toBe'](0x0),expect((await a['getTask'](NET,b['id']))['status'])['toBe']('dismissed'),c=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x190n,0x2)],0xbb8),expect(c['revived'])['toBe'](0x1);const d=await a['getTask'](NET,b['id']);expect(d['status'])['toBe']('pending'),expect(d['resolution'])['toBeUndefined'](),expect(d['resolved_at'])['toBeUndefined']();}),it('executed\x20tasks\x20are\x20terminal\x20—\x20same\x20dedupe_key\x20never\x20re-opens\x20them',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);const b=(await a['listTasks'](NET))[0x0];await a['resolveTask'](NET,b['id'],'auto_executed',0x5dc,'tx\x20ABC','krule_1');const c=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x1f4n)],0x7d0);expect(c)['toEqual']({'opened':0x0,'refreshed':0x0,'revived':0x0,'superseded':0x0});const d=await a['getTask'](NET,b['id']);expect(d['status'])['toBe']('executed'),expect(d['rule_id'])['toBe']('krule_1');}),it('supersedes\x20pending\x20tasks\x20of\x20THIS\x20detector\x20only',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8),await a['upsertDesired'](NET,'progress_actionable',[{'dedupe_key':'progress_actionable:0xp1:0xaaa111:shipped|deliver','detector':'progress_actionable','beneficiary':ACCT,'title':'Workflow\x20action\x20available','state_fingerprint':'1:1::named_operator'}],0x3e8);const b=await a['upsertDesired'](NET,'payment_unclaimed',[],0x7d0);expect(b['superseded'])['toBe'](0x1);const c=await a['listTasks'](NET),d=c['find'](f=>f['detector']==='payment_unclaimed'),e=c['find'](f=>f['detector']==='progress_actionable');expect(d['status'])['toBe']('superseded'),expect(d['resolution'])['toBe']('superseded'),expect(e['status'])['toBe']('pending');}),it('execute_failed\x20keeps\x20the\x20task\x20pending\x20with\x20failure\x20bookkeeping',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);const b=(await a['listTasks'](NET))[0x0];await a['resolveTask'](NET,b['id'],'execute_failed',0x1388,'insufficient\x20gas','krule_1');const c=await a['getTask'](NET,b['id']);expect(c['status'])['toBe']('pending'),expect(c['last_auto_attempt_at'])['toBe'](0x1388),expect(c['auto_attempts'])['toBe'](0x1),expect(c['resolution_note'])['toBe']('insufficient\x20gas');});}),describe('detectPaymentUnclaimed',()=>{it('emits\x20a\x20claim-to-self\x20task\x20for\x20accounts\x20with\x20unclaimed\x20wrappers',async()=>{const a=await detectPaymentUnclaimed([ACCT['toUpperCase'](),OTHER,'0xccc333'],NET,{'queryUnclaimed':async c=>{if(c===ACCT)return{'balance':0x64n,'count':0x2,'token_type':'0x2::sui::SUI'};if(c===OTHER)return{'balance':0x0n,'count':0x0};throw new Error('rpc\x20down');},'formatAmount':async()=>'0.0000001\x20SUI'});expect(a)['toHaveLength'](0x1);const b=a[0x0];expect(b['dedupe_key'])['toBe']('payment_unclaimed:'+ACCT),expect(b['beneficiary'])['toBe'](ACCT),expect(b['operation'])['toEqual']({'operation_type':'payment','data':{'receive':!![]}}),expect(b['state_fingerprint'])['toBe']('2:100'),expect(b['title'])['toContain']('0.0000001\x20SUI');}),it('falls\x20back\x20to\x20raw\x20units\x20when\x20formatting\x20fails',async()=>{const a=await detectPaymentUnclaimed([ACCT],NET,{'queryUnclaimed':async()=>({'balance':0x2an,'count':0x1}),'formatAmount':async()=>{throw new Error('no\x20metadata');}});expect(a[0x0]['title'])['toContain']('42\x20(smallest\x20unit)');});}),describe('detectProgressActionable',()=>{const a='0xprog1',b='0xmachine1',c=[{'name':'shipped','pairs':[{'prev_node':'start','threshold':0x1,'forwards':[{'name':'deliver','weight':0x1,'namedOperator':'courier'}]}]}],d=(g=[])=>({'machine':b,'current':'start','session':g,'namedOperator':[{'name':'courier','operators':[ACCT]}]}),e=g=>({'fetchProgressFields':async()=>new Map([[a,g]]),'fetchMachineNodes':async()=>c,'fetchMachinePermissionAddr':async()=>undefined,'fetchPermissionContext':async()=>undefined,'fetchOrderContext':async()=>undefined}),f=makeScope({'order_children':[{'type':'progress','object':a}]});it('routes\x20an\x20actionable\x20forward\x20to\x20its\x20named\x20operator',async()=>{const g=await detectProgressActionable(f,NET,e(d()),0x14);expect(g)['toHaveLength'](0x1),expect(g[0x0]['dedupe_key'])['toBe']('progress_actionable:'+a+':'+ACCT+':shipped|deliver'),expect(g[0x0]['beneficiary'])['toBe'](ACCT),expect(g[0x0]['operation'])['toBeUndefined'](),expect(g[0x0]['detail'])['toContain']('workflow_operation');}),it('omits\x20accomplished\x20forwards\x20(single-operator\x20lock)',async()=>{const g=[{'next_node':'shipped','forwards':[{'forward':'deliver','who':ACCT,'accomplished':!![]}]}],h=await detectProgressActionable(f,NET,e(d(g)),0x14);expect(h)['toHaveLength'](0x0);}),it('restricts\x20a\x20held\x20forward\x20to\x20its\x20holder',async()=>{const g=[{'next_node':'shipped','forwards':[{'forward':'deliver','who':OTHER,'accomplished':![]}]}],h=await detectProgressActionable(f,NET,e(d(g)),0x14);expect(h)['toHaveLength'](0x0);}),it('returns\x20nothing\x20when\x20the\x20batch\x20read\x20fails\x20(fail-safe)',async()=>{const g=await detectProgressActionable(f,NET,{...e(d()),'fetchProgressFields':async()=>{throw new Error('rpc\x20down');}},0x14);expect(g)['toEqual']([]);});});function scanDepsFor(a,b){let c=0x2710;const d=[],e={'store':a,'payment':{'queryUnclaimed':async()=>({'balance':0x64n,'count':0x1})},'progress':{'fetchProgressFields':async()=>new Map(),'fetchMachineNodes':async()=>[],'fetchMachinePermissionAddr':async()=>undefined,'fetchPermissionContext':async()=>undefined,'fetchOrderContext':async()=>undefined},'execute':async f=>{return d['push']({'operation_type':f['operation_type'],'account':f['account'],'via':f['via']}),{'ok':!![],'digest':'DIGEST1'};},'now':()=>c,'logger':()=>{},...b};return{'deps':e,'executed':d,'advance':f=>{c+=f;},'setClock':f=>{c=f;}};}describe('runKeeperScan',()=>{it('skips\x20when\x20disabled\x20and\x20when\x20inside\x20the\x20cadence\x20interval',async()=>{const a=makeStore(),{deps:b}=scanDepsFor(a);await a['saveConfig'](NET,{'enabled':![]});let c=await runKeeperScan(NET,makeScope(),b);expect(c['scanned'])['toBe'](![]),expect(c['reason'])['toBe']('disabled'),await a['saveConfig'](NET,{'enabled':!![]}),await a['setLastScanAt'](NET,0x2710),c=await runKeeperScan(NET,makeScope(),b),expect(c['scanned'])['toBe'](![]),expect(c['reason'])['toBe']('interval');}),it('auto-executes\x20a\x20payment\x20task\x20ONLY\x20with\x20a\x20covering\x20enabled\x20rule',async()=>{const a=makeStore(),{deps:b,executed:c}=scanDepsFor(a);let d=await runKeeperScan(NET,makeScope(),b,{'force':!![]});expect(d['opened'])['toBe'](0x1),expect(d['auto_executed'])['toBe'](0x0),expect(c)['toHaveLength'](0x0),await a['upsertRule'](NET,{'id':'krule_1','enabled':!![],'detector':'payment_unclaimed','accounts':[],'auto_execute':!![],'created_at':0x0}),d=await runKeeperScan(NET,makeScope(),b,{'force':!![]}),expect(d['auto_executed'])['toBe'](0x1),expect(c[0x0])['toEqual']({'operation_type':'payment','account':ACCT,'via':'rule\x20krule_1'});const e=(await a['listTasks'](NET))[0x0];expect(e['status'])['toBe']('executed'),expect(e['resolution'])['toBe']('auto_executed'),expect(e['rule_id'])['toBe']('krule_1'),expect(e['resolution_note'])['toContain']('DIGEST1');}),it('never\x20auto-executes\x20progress\x20tasks\x20(reminder-only\x20boundary)',async()=>{const a=makeStore(),{deps:b,executed:c}=scanDepsFor(a,{'payment':{'queryUnclaimed':async()=>null},'progress':{'fetchProgressFields':async()=>new Map([['0xprog1',{'machine':'0xm1','current':'start','session':[],'namedOperator':[{'name':'courier','operators':[ACCT]}]}]]),'fetchMachineNodes':async()=>[{'name':'shipped','pairs':[{'prev_node':'start','threshold':0x1,'forwards':[{'name':'deliver','weight':0x1,'namedOperator':'courier'}]}]}],'fetchMachinePermissionAddr':async()=>undefined,'fetchPermissionContext':async()=>undefined,'fetchOrderContext':async()=>undefined}});await a['upsertRule'](NET,{'id':'krule_p','enabled':!![],'detector':'progress_actionable','accounts':[],'auto_execute':!![],'created_at':0x0});const d=await runKeeperScan(NET,makeScope({'order_children':[{'type':'progress','object':'0xprog1'}]}),b,{'force':!![]});expect(d['opened'])['toBe'](0x1),expect(d['auto_executed'])['toBe'](0x0),expect(c)['toHaveLength'](0x0),expect((await a['listTasks'](NET))[0x0]['status'])['toBe']('pending');}),it('backs\x20off\x20after\x20a\x20failed\x20auto-exec\x20until\x20the\x20cooldown\x20passes',async()=>{const a=makeStore(),b=scanDepsFor(a,{'execute':async()=>({'ok':![],'error':'insufficient\x20gas'})});await a['upsertRule'](NET,{'id':'krule_1','enabled':!![],'detector':'payment_unclaimed','accounts':[],'auto_execute':!![],'created_at':0x0});let c=await runKeeperScan(NET,makeScope(),b['deps'],{'force':!![]});expect(c['auto_failed'])['toBe'](0x1);const d=(await a['listTasks'](NET))[0x0];expect(d['status'])['toBe']('pending'),expect(d['resolution_note'])['toBe']('insufficient\x20gas'),c=await runKeeperScan(NET,makeScope(),b['deps'],{'force':!![]}),expect(c['auto_failed'])['toBe'](0x0),expect(c['auto_executed'])['toBe'](0x0),b['advance'](0x1f*0xea60),c=await runKeeperScan(NET,makeScope(),b['deps'],{'force':!![]}),expect(c['auto_failed'])['toBe'](0x1);}),it('caps\x20auto-executions\x20per\x20scan\x20(gas\x20guard)',async()=>{const a=makeStore(),{deps:b,executed:c}=scanDepsFor(a);await a['saveConfig'](NET,{'max_auto_execute_per_scan':0x1}),await a['upsertRule'](NET,{'id':'krule_1','enabled':!![],'detector':'payment_unclaimed','accounts':[],'auto_execute':!![],'created_at':0x0});const d=makeScope({'accounts':[ACCT,OTHER]}),e=await runKeeperScan(NET,d,b,{'force':!![]});expect(e['opened'])['toBe'](0x2),expect(e['auto_executed'])['toBe'](0x1),expect(c)['toHaveLength'](0x1),expect(await a['listTasks'](NET,{'status':'pending'}))['toHaveLength'](0x1);});}),describe('executeKeeperTask\x20(manual)',()=>{it('resolves\x20a\x20payment\x20task\x20as\x20manual_executed',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);const b=(await a['listTasks'](NET))[0x0],{deps:c}=scanDepsFor(a),d=await executeKeeperTask(NET,b,c);expect(d['ok'])['toBe'](!![]);const e=await a['getTask'](NET,b['id']);expect(e['status'])['toBe']('executed'),expect(e['resolution'])['toBe']('manual_executed');}),it('refuses\x20reminder-only\x20tasks\x20(progress)\x20with\x20guidance',async()=>{const a=makeStore(),{deps:b}=scanDepsFor(a),c={'id':'ktask_x','dedupe_key':'progress_actionable:0xp:0xaaa111:shipped|deliver','detector':'progress_actionable','network':NET,'beneficiary':ACCT,'title':'Workflow\x20action\x20available','state_fingerprint':'1:1::named_operator','status':'pending','created_at':0x0,'updated_at':0x0},d=await executeKeeperTask(NET,c,b);expect(d['ok'])['toBe'](![]),expect(d['error'])['toContain']('reminder-only');});});
|
|
1
|
+
import{describe,expect,it}from'vitest';import{KeeperStore}from'./KeeperStore.js';import{detectPaymentUnclaimed,detectProgressActionable}from'./detectors.js';import{executeKeeperTask,runKeeperScan}from'./KeeperScan.js';import{clampKeeperConfig,defaultKeeperConfig,KEEPER_MIN}from'./types.js';const NET='testnet',ACCT='0xaaa111',OTHER='0xbbb222';function memStorage(){const a=new Map();return{'get':async b=>a['get'](b),'put':async(b,c)=>void a['set'](b,c)};}function makeStore(){return new KeeperStore(memStorage());}function paymentItem(a,b,c=0x1){return{'dedupe_key':'payment_unclaimed:'+a,'detector':'payment_unclaimed','beneficiary':a,'operation':{'operation_type':'payment','data':{'receive':!![]}},'title':'Unclaimed\x20funds\x20—\x20'+b+'\x20waiting','state_fingerprint':c+':'+b['toString']()};}function makeScope(a){return{'version':0x1,'resolved_at':0x0,'accounts':[ACCT],'permissions':[],'managed_objects':[],'services':[],'orders':[],'order_children':[],'focus':[],'index':{},...a};}describe('keeper\x20config',()=>{it('returns\x20safe\x20defaults:\x20reminders\x20ON,\x20auto\x20rules\x20none',async()=>{const a=makeStore(),b=await a['getConfig'](NET);expect(b['enabled'])['toBe'](!![]),expect(b['detectors']['payment_unclaimed'])['toBe'](!![]),expect(b['detectors']['progress_actionable'])['toBe'](!![]),expect(await a['listRules'](NET))['toEqual']([]);}),it('config_set\x20patch\x20merges\x20detectors\x20individually',async()=>{const a=makeStore(),b=await a['saveConfig'](NET,{'detectors':{'payment_unclaimed':![]}});expect(b['detectors']['payment_unclaimed'])['toBe'](![]),expect(b['detectors']['progress_actionable'])['toBe'](!![]);const c=await a['getConfig'](NET);expect(c['detectors']['payment_unclaimed'])['toBe'](![]),expect(c['detectors']['progress_actionable'])['toBe'](!![]);}),it('clamps\x20numeric\x20bounds\x20(cost/gas\x20guards)',()=>{const a=clampKeeperConfig({...defaultKeeperConfig(),'scan_interval_ms':0x1,'max_scan_objects':0x0,'max_auto_execute_per_scan':0x0,'auto_retry_cooldown_ms':0x0});expect(a['scan_interval_ms'])['toBe'](KEEPER_MIN['scan_interval_ms']),expect(a['max_scan_objects'])['toBe'](KEEPER_MIN['max_scan_objects']),expect(a['max_auto_execute_per_scan'])['toBe'](KEEPER_MIN['max_auto_execute_per_scan']),expect(a['auto_retry_cooldown_ms'])['toBe'](KEEPER_MIN['auto_retry_cooldown_ms']);});}),describe('keeper\x20rules',()=>{const a=b=>({'id':'krule_1','enabled':!![],'detector':'payment_unclaimed','accounts':[],'auto_execute':!![],'created_at':0x0,...b});it('matchingAutoRules\x20honors\x20enabled\x20/\x20auto_execute\x20/\x20account\x20coverage',async()=>{const b=makeStore();await b['upsertRule'](NET,a()),expect(await b['matchingAutoRules'](NET,'payment_unclaimed',ACCT))['toHaveLength'](0x1),expect(await b['matchingAutoRules'](NET,'progress_actionable',ACCT))['toHaveLength'](0x0),await b['upsertRule'](NET,a({'id':'krule_2','accounts':[OTHER['toUpperCase']()]})),expect(await b['matchingAutoRules'](NET,'payment_unclaimed',ACCT))['toHaveLength'](0x1),expect(await b['matchingAutoRules'](NET,'payment_unclaimed',OTHER))['toHaveLength'](0x2),await b['upsertRule'](NET,a({'id':'krule_3','enabled':![]})),await b['upsertRule'](NET,a({'id':'krule_4','auto_execute':![]}));const c=await b['matchingAutoRules'](NET,'payment_unclaimed',OTHER);expect(c['map'](d=>d['id'])['sort']())['toEqual'](['krule_1','krule_2']);});}),describe('KeeperStore.upsertDesired',()=>{it('opens\x20new\x20tasks,\x20refreshes\x20on\x20fingerprint\x20change,\x20no\x20churn\x20when\x20identical',async()=>{const a=makeStore();let b=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);expect(b)['toEqual']({'opened':0x1,'refreshed':0x0,'revived':0x0,'superseded':0x0}),b=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x7d0),expect(b)['toEqual']({'opened':0x0,'refreshed':0x0,'revived':0x0,'superseded':0x0}),b=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0xfan)],0xbb8),expect(b)['toEqual']({'opened':0x0,'refreshed':0x1,'revived':0x0,'superseded':0x0});const c=(await a['listTasks'](NET))[0x0];expect(c['title'])['toContain']('250'),expect(c['updated_at'])['toBe'](0xbb8);}),it('dismissed\x20stays\x20dismissed\x20for\x20identical\x20state,\x20revives\x20on\x20material\x20change',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);const b=(await a['listTasks'](NET))[0x0];await a['resolveTask'](NET,b['id'],'dismissed',0x5dc,'not\x20now');let c=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x7d0);expect(c['revived'])['toBe'](0x0),expect((await a['getTask'](NET,b['id']))['status'])['toBe']('dismissed'),c=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x190n,0x2)],0xbb8),expect(c['revived'])['toBe'](0x1);const d=await a['getTask'](NET,b['id']);expect(d['status'])['toBe']('pending'),expect(d['resolution'])['toBeUndefined'](),expect(d['resolved_at'])['toBeUndefined']();}),it('executed\x20tasks\x20are\x20terminal\x20—\x20same\x20dedupe_key\x20never\x20re-opens\x20them',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);const b=(await a['listTasks'](NET))[0x0];await a['resolveTask'](NET,b['id'],'auto_executed',0x5dc,'tx\x20ABC','krule_1');const c=await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x1f4n)],0x7d0);expect(c)['toEqual']({'opened':0x0,'refreshed':0x0,'revived':0x0,'superseded':0x0});const d=await a['getTask'](NET,b['id']);expect(d['status'])['toBe']('executed'),expect(d['rule_id'])['toBe']('krule_1');}),it('supersedes\x20pending\x20tasks\x20of\x20THIS\x20detector\x20only',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8),await a['upsertDesired'](NET,'progress_actionable',[{'dedupe_key':'progress_actionable:0xp1:0xaaa111:shipped|deliver','detector':'progress_actionable','beneficiary':ACCT,'title':'Workflow\x20action\x20available','state_fingerprint':'1:1::named_operator'}],0x3e8);const b=await a['upsertDesired'](NET,'payment_unclaimed',[],0x7d0);expect(b['superseded'])['toBe'](0x1);const c=await a['listTasks'](NET),d=c['find'](f=>f['detector']==='payment_unclaimed'),e=c['find'](f=>f['detector']==='progress_actionable');expect(d['status'])['toBe']('superseded'),expect(d['resolution'])['toBe']('superseded'),expect(e['status'])['toBe']('pending');}),it('execute_failed\x20keeps\x20the\x20task\x20pending\x20with\x20failure\x20bookkeeping',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);const b=(await a['listTasks'](NET))[0x0];await a['resolveTask'](NET,b['id'],'execute_failed',0x1388,'insufficient\x20gas','krule_1');const c=await a['getTask'](NET,b['id']);expect(c['status'])['toBe']('pending'),expect(c['last_auto_attempt_at'])['toBe'](0x1388),expect(c['auto_attempts'])['toBe'](0x1),expect(c['resolution_note'])['toBe']('insufficient\x20gas');});}),describe('detectPaymentUnclaimed',()=>{it('emits\x20a\x20claim-to-self\x20task\x20for\x20accounts\x20with\x20unclaimed\x20wrappers',async()=>{const a=await detectPaymentUnclaimed([ACCT['toUpperCase'](),OTHER,'0xccc333'],NET,{'queryUnclaimed':async c=>{if(c===ACCT)return{'balance':0x64n,'count':0x2,'token_type':'0x2::wow::WOW'};if(c===OTHER)return{'balance':0x0n,'count':0x0};throw new Error('rpc\x20down');},'formatAmount':async()=>'0.0000001\x20WOW'});expect(a)['toHaveLength'](0x1);const b=a[0x0];expect(b['dedupe_key'])['toBe']('payment_unclaimed:'+ACCT),expect(b['beneficiary'])['toBe'](ACCT),expect(b['operation'])['toEqual']({'operation_type':'payment','data':{'receive':!![]}}),expect(b['state_fingerprint'])['toBe']('2:100'),expect(b['title'])['toContain']('0.0000001\x20WOW');}),it('falls\x20back\x20to\x20raw\x20units\x20when\x20formatting\x20fails',async()=>{const a=await detectPaymentUnclaimed([ACCT],NET,{'queryUnclaimed':async()=>({'balance':0x2an,'count':0x1}),'formatAmount':async()=>{throw new Error('no\x20metadata');}});expect(a[0x0]['title'])['toContain']('42\x20(smallest\x20unit)');});}),describe('detectProgressActionable',()=>{const a='0xprog1',b='0xmachine1',c=[{'name':'shipped','pairs':[{'prev_node':'start','threshold':0x1,'forwards':[{'name':'deliver','weight':0x1,'namedOperator':'courier'}]}]}],d=(g=[])=>({'machine':b,'current':'start','session':g,'namedOperator':[{'name':'courier','operators':[ACCT]}]}),e=g=>({'fetchProgressFields':async()=>new Map([[a,g]]),'fetchMachineNodes':async()=>c,'fetchMachinePermissionAddr':async()=>undefined,'fetchPermissionContext':async()=>undefined,'fetchOrderContext':async()=>undefined}),f=makeScope({'order_children':[{'type':'progress','object':a}]});it('routes\x20an\x20actionable\x20forward\x20to\x20its\x20named\x20operator',async()=>{const g=await detectProgressActionable(f,NET,e(d()),0x14);expect(g)['toHaveLength'](0x1),expect(g[0x0]['dedupe_key'])['toBe']('progress_actionable:'+a+':'+ACCT+':shipped|deliver'),expect(g[0x0]['beneficiary'])['toBe'](ACCT),expect(g[0x0]['operation'])['toBeUndefined'](),expect(g[0x0]['detail'])['toContain']('workflow_operation');}),it('omits\x20accomplished\x20forwards\x20(single-operator\x20lock)',async()=>{const g=[{'next_node':'shipped','forwards':[{'forward':'deliver','who':ACCT,'accomplished':!![]}]}],h=await detectProgressActionable(f,NET,e(d(g)),0x14);expect(h)['toHaveLength'](0x0);}),it('restricts\x20a\x20held\x20forward\x20to\x20its\x20holder',async()=>{const g=[{'next_node':'shipped','forwards':[{'forward':'deliver','who':OTHER,'accomplished':![]}]}],h=await detectProgressActionable(f,NET,e(d(g)),0x14);expect(h)['toHaveLength'](0x0);}),it('returns\x20nothing\x20when\x20the\x20batch\x20read\x20fails\x20(fail-safe)',async()=>{const g=await detectProgressActionable(f,NET,{...e(d()),'fetchProgressFields':async()=>{throw new Error('rpc\x20down');}},0x14);expect(g)['toEqual']([]);});});function scanDepsFor(a,b){let c=0x2710;const d=[],e={'store':a,'payment':{'queryUnclaimed':async()=>({'balance':0x64n,'count':0x1})},'progress':{'fetchProgressFields':async()=>new Map(),'fetchMachineNodes':async()=>[],'fetchMachinePermissionAddr':async()=>undefined,'fetchPermissionContext':async()=>undefined,'fetchOrderContext':async()=>undefined},'execute':async f=>{return d['push']({'operation_type':f['operation_type'],'account':f['account'],'via':f['via']}),{'ok':!![],'digest':'DIGEST1'};},'now':()=>c,'logger':()=>{},...b};return{'deps':e,'executed':d,'advance':f=>{c+=f;},'setClock':f=>{c=f;}};}describe('runKeeperScan',()=>{it('skips\x20when\x20disabled\x20and\x20when\x20inside\x20the\x20cadence\x20interval',async()=>{const a=makeStore(),{deps:b}=scanDepsFor(a);await a['saveConfig'](NET,{'enabled':![]});let c=await runKeeperScan(NET,makeScope(),b);expect(c['scanned'])['toBe'](![]),expect(c['reason'])['toBe']('disabled'),await a['saveConfig'](NET,{'enabled':!![]}),await a['setLastScanAt'](NET,0x2710),c=await runKeeperScan(NET,makeScope(),b),expect(c['scanned'])['toBe'](![]),expect(c['reason'])['toBe']('interval');}),it('auto-executes\x20a\x20payment\x20task\x20ONLY\x20with\x20a\x20covering\x20enabled\x20rule',async()=>{const a=makeStore(),{deps:b,executed:c}=scanDepsFor(a);let d=await runKeeperScan(NET,makeScope(),b,{'force':!![]});expect(d['opened'])['toBe'](0x1),expect(d['auto_executed'])['toBe'](0x0),expect(c)['toHaveLength'](0x0),await a['upsertRule'](NET,{'id':'krule_1','enabled':!![],'detector':'payment_unclaimed','accounts':[],'auto_execute':!![],'created_at':0x0}),d=await runKeeperScan(NET,makeScope(),b,{'force':!![]}),expect(d['auto_executed'])['toBe'](0x1),expect(c[0x0])['toEqual']({'operation_type':'payment','account':ACCT,'via':'rule\x20krule_1'});const e=(await a['listTasks'](NET))[0x0];expect(e['status'])['toBe']('executed'),expect(e['resolution'])['toBe']('auto_executed'),expect(e['rule_id'])['toBe']('krule_1'),expect(e['resolution_note'])['toContain']('DIGEST1');}),it('never\x20auto-executes\x20progress\x20tasks\x20(reminder-only\x20boundary)',async()=>{const a=makeStore(),{deps:b,executed:c}=scanDepsFor(a,{'payment':{'queryUnclaimed':async()=>null},'progress':{'fetchProgressFields':async()=>new Map([['0xprog1',{'machine':'0xm1','current':'start','session':[],'namedOperator':[{'name':'courier','operators':[ACCT]}]}]]),'fetchMachineNodes':async()=>[{'name':'shipped','pairs':[{'prev_node':'start','threshold':0x1,'forwards':[{'name':'deliver','weight':0x1,'namedOperator':'courier'}]}]}],'fetchMachinePermissionAddr':async()=>undefined,'fetchPermissionContext':async()=>undefined,'fetchOrderContext':async()=>undefined}});await a['upsertRule'](NET,{'id':'krule_p','enabled':!![],'detector':'progress_actionable','accounts':[],'auto_execute':!![],'created_at':0x0});const d=await runKeeperScan(NET,makeScope({'order_children':[{'type':'progress','object':'0xprog1'}]}),b,{'force':!![]});expect(d['opened'])['toBe'](0x1),expect(d['auto_executed'])['toBe'](0x0),expect(c)['toHaveLength'](0x0),expect((await a['listTasks'](NET))[0x0]['status'])['toBe']('pending');}),it('backs\x20off\x20after\x20a\x20failed\x20auto-exec\x20until\x20the\x20cooldown\x20passes',async()=>{const a=makeStore(),b=scanDepsFor(a,{'execute':async()=>({'ok':![],'error':'insufficient\x20gas'})});await a['upsertRule'](NET,{'id':'krule_1','enabled':!![],'detector':'payment_unclaimed','accounts':[],'auto_execute':!![],'created_at':0x0});let c=await runKeeperScan(NET,makeScope(),b['deps'],{'force':!![]});expect(c['auto_failed'])['toBe'](0x1);const d=(await a['listTasks'](NET))[0x0];expect(d['status'])['toBe']('pending'),expect(d['resolution_note'])['toBe']('insufficient\x20gas'),c=await runKeeperScan(NET,makeScope(),b['deps'],{'force':!![]}),expect(c['auto_failed'])['toBe'](0x0),expect(c['auto_executed'])['toBe'](0x0),b['advance'](0x1f*0xea60),c=await runKeeperScan(NET,makeScope(),b['deps'],{'force':!![]}),expect(c['auto_failed'])['toBe'](0x1);}),it('caps\x20auto-executions\x20per\x20scan\x20(gas\x20guard)',async()=>{const a=makeStore(),{deps:b,executed:c}=scanDepsFor(a);await a['saveConfig'](NET,{'max_auto_execute_per_scan':0x1}),await a['upsertRule'](NET,{'id':'krule_1','enabled':!![],'detector':'payment_unclaimed','accounts':[],'auto_execute':!![],'created_at':0x0});const d=makeScope({'accounts':[ACCT,OTHER]}),e=await runKeeperScan(NET,d,b,{'force':!![]});expect(e['opened'])['toBe'](0x2),expect(e['auto_executed'])['toBe'](0x1),expect(c)['toHaveLength'](0x1),expect(await a['listTasks'](NET,{'status':'pending'}))['toHaveLength'](0x1);});}),describe('executeKeeperTask\x20(manual)',()=>{it('resolves\x20a\x20payment\x20task\x20as\x20manual_executed',async()=>{const a=makeStore();await a['upsertDesired'](NET,'payment_unclaimed',[paymentItem(ACCT,0x64n)],0x3e8);const b=(await a['listTasks'](NET))[0x0],{deps:c}=scanDepsFor(a),d=await executeKeeperTask(NET,b,c);expect(d['ok'])['toBe'](!![]);const e=await a['getTask'](NET,b['id']);expect(e['status'])['toBe']('executed'),expect(e['resolution'])['toBe']('manual_executed');}),it('refuses\x20reminder-only\x20tasks\x20(progress)\x20with\x20guidance',async()=>{const a=makeStore(),{deps:b}=scanDepsFor(a),c={'id':'ktask_x','dedupe_key':'progress_actionable:0xp:0xaaa111:shipped|deliver','detector':'progress_actionable','network':NET,'beneficiary':ACCT,'title':'Workflow\x20action\x20available','state_fingerprint':'1:1::named_operator','status':'pending','created_at':0x0,'updated_at':0x0},d=await executeKeeperTask(NET,c,b);expect(d['ok'])['toBe'](![]),expect(d['error'])['toContain']('reminder-only');});});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{mkdtempSync,writeFileSync}from'node:fs';import{tmpdir}from'node:os';import{join}from'node:path';import{afterAll,beforeAll,describe,expect,it}from'vitest';import{beginPolicyRun,endPolicyRun,factoryRulePack,getJudgmentDoc,judgmentStatus}from'../config/judgment.js';import{evaluateRuleBook}from'../config/rule-engine.js';import{serviceAllocatorAuditNodeAnalyzer}from'./service-allocator-audit-node.js';const CONFIG_DIR=mkdtempSync(join(tmpdir(),'wowok-alloc-audit-'));process['env']['WOWOK_CONFIG_DIR']=CONFIG_DIR;const PACK_IDS=['RC-FIND-01','RC-FIND-02','RC-FIND-03','RC-FIND-04','RC-FIND-05','RC-FIND-06','RC-FIND-07','RC-FIND-08','RC-GAP','RC-SUMMARY'];function rule(a,b){const c=factoryRulePack('alloc_audit');if(!c)throw new Error('alloc_audit\x20factory\x20pack\x20missing');const d=c['rules']['find'](e=>e['rule_id']===a);if(!d)throw new Error('rule\x20'+a+'\x20missing');return evaluateRuleBook([d],b)['findings'][0x0];}const BASE={'host_service':'0xsvc','code':'RC-FIND-01','base_level':'high','evidence_paths':'(root)','evidence_count':0x0};function resnapshot(){endPolicyRun(),beginPolicyRun();}beforeAll(()=>{beginPolicyRun();}),afterAll(()=>{endPolicyRun();}),describe('alloc_audit\x20factory\x20parity\x20—\x20per-finding\x20rules',()=>{it('the\x20pack\x20carries\x20exactly\x20the\x20canonical\x20emission\x20ids',()=>{const a=factoryRulePack('alloc_audit');expect(a)['not']['toBeNull'](),expect(a['rules']['map'](b=>b['rule_id'])['sort']())['toEqual']([...PACK_IDS]['sort']());}),it('fact:base_level\x20passes\x20the\x20kernel\x20severity\x20through\x20unchanged',()=>{for(const a of['high','medium','low']){expect(rule('RC-FIND-01',{...BASE,'base_level':a})?.['level'])['toBe'](a);}}),it('copy\x20is\x20pack-owned\x20and\x20interpolates\x20the\x20kernel\x20facts',()=>{const a=rule('RC-FIND-01',{...BASE,'evidence_paths':'root.and(0)'});expect(a?.['title'])['toBe']('Fund\x20theft\x20risk:\x20Signer\x20recipient\x20without\x20caller\x20identity\x20constraint'),expect(a?.['description'])['toContain']('service\x200xsvc'),expect(a?.['description'])['toContain']('rule\x20RC-FIND-01,\x20evidence\x20paths\x20root.and(0)'),expect(a?.['mitigation'])['toContain']('do\x20NOT\x20pay\x20this\x20service\x20before\x20the\x20fix');}),it('fixed\x20levels\x20hold\x20where\x20the\x20kernel\x20hardcoded\x20them',()=>{expect(rule('RC-FIND-05',{...BASE,'code':'RC-FIND-05','base_level':'high'})?.['level'])['toBe']('medium'),expect(rule('RC-FIND-06',{...BASE,'code':'RC-FIND-06','base_level':'high'})?.['level'])['toBe']('low'),expect(rule('RC-FIND-07',{...BASE,'code':'RC-FIND-07','base_level':'high'})?.['level'])['toBe']('medium');}),it('shortfall\x20findings\x20(05/07)\x20carry\x20loss\x20parties\x20only\x20and\x20are\x20never\x20downgraded',()=>{for(const a of['RC-FIND-05','RC-FIND-07']){const b=rule(a,{...BASE,'code':a});expect(b?.['exposure']?.['gainPaths'])['toHaveLength'](0x0),expect(b?.['exposure']?.['lossParties']['length'])['toBeGreaterThan'](0x0),expect(b?.['exposure']?.['verdict'])['toBe']('confirmed'),expect(b?.['level'])['not']['toBe']('info');}expect(rule('RC-FIND-05',{...BASE,'code':'RC-FIND-05'})?.['exposure']?.['lossParties']['map'](c=>c['role']))['toEqual'](['supplier','buyer']);}),it('RC-FIND-08\x20keeps\x20its\x20level\x20as\x20pending-disclosure\x20(undecided\x20predicate)',()=>{const a=rule('RC-FIND-08',{...BASE,'code':'RC-FIND-08','base_level':'medium','evidence_count':0x2});expect(a?.['level'])['toBe']('medium'),expect(a?.['description'])['toContain']('composes\x202\x20sub-guard(s)'),expect(a?.['exposure']?.['verdict'])['toBe']('pending-disclosure'),expect(a?.['exposure']?.['gainPaths'][0x0]?.['viability'])['toBe']('unverifiable');}),it('an\x20unknown\x20canonical\x20code\x20fires\x20no\x20case\x20(kernel\x20fallback\x20stays\x20in\x20charge)',()=>{const a=factoryRulePack('alloc_audit'),b=a['rules']['find'](d=>d['rule_id']==='RC-FIND-01'),{findings:c}=evaluateRuleBook([b],{...BASE,'code':'RC-FIND-99'});expect(c)['toHaveLength'](0x0);});}),describe('alloc_audit\x20factory\x20parity\x20—\x20gap\x20and\x20verdict',()=>{it('RC-GAP\x20emits\x20info\x20with\x20the\x20unfetched\x20evidence\x20interpolated',()=>{const a=rule('RC-GAP',{'host_service':'0xsvc','unfetched_count':0x2,'unfetched_list':'0xa,\x200xb\x20(guard.relies)'});expect(a?.['level'])['toBe']('info'),expect(a?.['title'])['toContain']('evidence\x20gap'),expect(a?.['description'])['toContain']('references\x202\x20guard(s)'),expect(a?.['description'])['toContain']('0xa,\x200xb\x20(guard.relies)'),expect(a?.['exposure']?.['gainPaths'])['toHaveLength'](0x0),expect(a?.['exposure']?.['verdict'])['toBe']('confirmed');}),it('RC-SUMMARY\x20—\x20unsafe\x20wins\x20at\x20high,\x20with\x20and\x20without\x20the\x20residual\x20suffix',()=>{const a=rule('RC-SUMMARY',summaryFacts({'dest_unsafe':!![],'resolution_required':![]}));expect(a?.['level'])['toBe']('high'),expect(a?.['title'])['toBe']('Fund\x20destination\x20and\x20condition\x20integrity:\x20stealable\x20destination\x20exists'),expect(a?.['description'])['toContain']('WARNING:\x20an\x20unbound\x20Signer\x20direct-pay\x20path\x20exists'),expect(a?.['exposure']?.['gainPaths'][0x0]?.['viability'])['toBe']('viable'),expect(a?.['exposure']?.['verdict'])['toBe']('confirmed');const b=rule('RC-SUMMARY',summaryFacts({'dest_unsafe':!![],'resolution_required':!![]}));expect(b?.['level'])['toBe']('high'),expect(b?.['title'])['toBe']('Fund\x20destination\x20and\x20condition\x20integrity:\x20stealable\x20destination\x20exists\x20(residual\x20requires\x20explicit\x20decision)');}),it('RC-SUMMARY\x20—\x20safe\x20+\x20residual\x20is\x20medium\x20conditional\x20with\x20the\x20destinations\x20interpolated',()=>{const a=rule('RC-SUMMARY',summaryFacts({'dest_unsafe':![],'resolution_required':!![]}));expect(a?.['level'])['toBe']('medium'),expect(a?.['title'])['toBe']('Fund\x20destination\x20and\x20condition\x20integrity:\x20destination\x20safe\x20(residual\x20requires\x20explicit\x20decision)'),expect(a?.['exposure']?.['gainPaths'][0x0]?.['viability'])['toBe']('conditional'),expect(a?.['exposure']?.['lossParties'][0x0]?.['basis'])['toContain']('0xmerchant'),expect(a?.['exposure']?.['verdict'])['toBe']('confirmed');}),it('RC-SUMMARY\x20—\x20fully\x20safe\x20downgrades\x20to\x20info\x20(redirect\x20provably\x20blocked)',()=>{const a=rule('RC-SUMMARY',summaryFacts({'dest_unsafe':![],'resolution_required':![]}));expect(a?.['level'])['toBe']('info'),expect(a?.['title'])['toBe']('Fund\x20destination\x20and\x20condition\x20integrity:\x20destination\x20safe'),expect(a?.['exposure']?.['gainPaths'][0x0]?.['viability'])['toBe']('blocked'),expect(a?.['exposure']?.['verdict'])['toBe']('downgraded'),expect(a?.['exposure']?.['baseSeverity'])['toBe']('info');});});function summaryFacts(a){return{'host_service':'0xsvc','allocator_count':0x1,'guard_count':0x1,'destinations_text':'0xmerchant','dest_unsafe':a['dest_unsafe'],'resolution_required':a['resolution_required'],'audit_summary':'Analyzed\x201\x20allocator(s):\x201\x20actionable,\x200\x20unavoidable.'};}const GUARD='0xguard0000000000000000000000000000000000000000000000000000000001';function serviceNode(){return{'id':'0xsvc','kind':'object','state':'fetched','origins':[],'depth':0x0,'raw':{'data':{'order_allocators':{'allocators':[{'guard':GUARD,'sharing':[{'who':{'Signer':!![]},'sharing':'10000','mode':'Rate'}]}]}}}};}function guardNode(){return{'id':GUARD,'kind':'object','state':'fetched','origins':[],'depth':0x1,'raw':{'data':{'table':[],'root':{'type':'value','value':!![]}}}};}function viewport(){return{'visibleEdges':[{'id':'service.order_allocator_guard|0xsvc→'+GUARD,'schema':'service.order_allocator_guard','family':'F','from':'0xsvc','to':GUARD,'retention':'complete','observedAt':0x0}],'graph':{'nodes':new Map([[GUARD,guardNode()]])}};}describe('alloc_audit\x20binding\x20—\x20end\x20to\x20end',()=>{it('a\x20signer-recipient\x20service\x20yields\x20the\x20pack-driven\x20theft\x20finding\x20+\x20unsafe\x20verdict',()=>{const a=serviceAllocatorAuditNodeAnalyzer['run'](serviceNode(),viewport());expect(a)['toHaveLength'](0x3);const [b,c,d]=a;expect(b['id'])['toBe']('ALC1:0xsvc#0'),expect(b['title'])['toBe']('Fund\x20theft\x20risk:\x20Signer\x20recipient\x20without\x20caller\x20identity\x20constraint'),expect(b['severity'])['toBe']('high'),expect(b['exposure']?.['verdict'])['toBe']('confirmed'),expect(b['exposure']?.['gainPaths'][0x0]?.['viability'])['toBe']('viable'),expect(b['detail'])['toContain']('service\x200xsvc'),expect(c['id'])['toBe']('ALC1:0xsvc#1'),expect(c['title'])['toBe']('Permissionless\x20alloc\x20—\x20settlement\x20timing\x20can\x20be\x20front-run'),expect(c['severity'])['toBe']('low'),expect(c['exposure']?.['verdict'])['toBe']('confirmed'),expect(d['id'])['toBe']('ALC1:0xsvc#2'),expect(d['title'])['toBe']('Fund\x20destination\x20and\x20condition\x20integrity:\x20stealable\x20destination\x20exists'),expect(d['severity'])['toBe']('high'),expect(d['detail'])['toContain']('1\x20allocator(s)\x20/\x201\x20resolved\x20guard(s)');}),it('a\x20user\x20disable\x20suppresses\x20the\x20theft\x20finding;\x20the\x20verdict\x20stays',()=>{writeFileSync(join(CONFIG_DIR,'judgment.json'),JSON['stringify']({'version':0x1,'rules':{'domains':{'alloc_audit':{'rules':[{'rule_id':'RC-FIND-01','enabled':![]}]}}}}),'utf-8'),resnapshot();const a=serviceAllocatorAuditNodeAnalyzer['run'](serviceNode(),viewport());expect(a['map'](c=>c['title']))['toEqual'](['Permissionless\x20alloc\x20—\x20settlement\x20timing\x20can\x20be\x20front-run','Fund\x20destination\x20and\x20condition\x20integrity:\x20stealable\x20destination\x20exists']);const b=judgmentStatus();expect(b['user_doc_loaded'])['toBe'](!![]);}),it('a\x20fact:\x20reference\x20outside\x20the\x20factory\x20vocabulary\x20is\x20rejected\x20loudly;\x20the\x20factory\x20keeps\x20serving',()=>{writeFileSync(join(CONFIG_DIR,'judgment.json'),JSON['stringify']({'version':0x1,'rules':{'domains':{'alloc_audit':{'rules':[{'rule_id':'RC-FIND-01','cases':[{'when':{'field':'code','op':'eq','value':'RC-FIND-01'},'level':'fact:not_a_kernel_fact','title':'t','description':'d'}]}]}}}}),'utf-8'),void getJudgmentDoc(),resnapshot();const a=judgmentStatus();expect(a['last_reload_error'])['toContain']('fact:not_a_kernel_fact'),expect(a['last_reload_error'])['toContain']('RC-FIND-01');const b=serviceAllocatorAuditNodeAnalyzer['run'](serviceNode(),viewport());expect(b['map'](c=>c['title']))['toEqual'](['Permissionless\x20alloc\x20—\x20settlement\x20timing\x20can\x20be\x20front-run','Fund\x20destination\x20and\x20condition\x20integrity:\x20stealable\x20destination\x20exists']);});});
|