{"version":3,"file":"plan-validator.mjs","names":[],"sources":["../../../src/services/plan-validator.ts"],"sourcesContent":["/**\n * Plan Validator — checks a Plan IR for contradictions, safety issues, and feasibility.\n *\n * Runs BEFORE a plan is scheduled or executed. Returns a ValidationResult with:\n * - Errors (plan cannot proceed)\n * - Warnings (plan can proceed but user should be aware)\n * - Info (suggestions for improvement)\n *\n * ─── Validation Passes ──────────────────────────────────────────────────\n *\n * 1. Structural  — all node IDs unique, refs resolve, no orphan nodes\n * 2. Temporal    — times are in the future, waits have bounds, no impossible schedules\n * 3. Financial   — no buying and selling the same token, no overspending, slippage sanity\n * 4. Tool        — referenced tools exist, params match schema, ownerOnly checks\n * 5. Safety      — loop bounds exist, total gas estimate reasonable, high-value warnings\n * 6. Dependency  — step outputs referenced before they're produced, circular refs\n */\n\nimport type {\n  Plan,\n  PlanNode,\n  ActionNode,\n  SequenceNode,\n  ParallelNode,\n  IfNode,\n  WaitNode,\n  LoopNode,\n  Condition,\n  CompareCondition,\n  ValueRef,\n  ValidationResult,\n  ValidationIssue,\n  IssueSeverity,\n  FailurePolicy,\n} from './plan-types.js';\nimport { CONTRADICTION_CODES } from './plan-types.js';\n\n// ─── Known Tools ────────────────────────────────────────────────────────\n// We don't import the actual tool registry to keep the validator self-contained.\n// This list is checked at plan creation time; unknown tools produce warnings, not errors.\n\nconst KNOWN_TOOLS = new Set([\n  'defi_swap', 'defi_price', 'defi_balance', 'transfer', 'manage_orders',\n  'analytics', 'market_intel', 'clawnch_info', 'clawnch_launch', 'clawnch_fees',\n  'clawnchconnect', 'crypto_workflow', 'cost_basis', 'permit2', 'liquidity',\n  'bridge', 'block_explorer', 'watch_activity', 'herd_intelligence',\n  'molten', 'clawnx', 'hummingbot', 'wayfinder',\n  'bankr_launch', 'bankr_automate', 'bankr_polymarket', 'bankr_leverage',\n]);\n\nconst WRITE_TOOLS = new Set([\n  'defi_swap', 'transfer', 'clawnch_launch', 'liquidity', 'bridge',\n  'permit2', 'bankr_launch', 'bankr_automate', 'bankr_polymarket', 'bankr_leverage',\n]);\n\nconst READ_TOOLS = new Set([\n  'defi_price', 'defi_balance', 'analytics', 'market_intel', 'clawnch_info',\n  'cost_basis', 'block_explorer', 'watch_activity', 'herd_intelligence', 'molten',\n]);\n\n// Tokens that are \"opposite\" sides of a trade\nconst TOKEN_ALIASES: Record<string, string> = {\n  WETH: 'ETH', weth: 'ETH', eth: 'ETH',\n  USDC: 'USD_STABLE', usdc: 'USD_STABLE',\n  USDT: 'USD_STABLE', usdt: 'USD_STABLE',\n  DAI: 'USD_STABLE', dai: 'USD_STABLE',\n};\n\nconst MAX_PLAN_DEPTH = 10;\nconst MAX_PLAN_NODES = 50;\nconst MAX_LOOP_ITERATIONS = 1000;\nconst HIGH_VALUE_ETH_THRESHOLD = 1.0;\nconst MAX_TOTAL_GAS_ETH = 0.5;\n\n// ─── Validator ──────────────────────────────────────────────────────────\n\nexport class PlanValidator {\n  private issues: ValidationIssue[] = [];\n  private nodeIds = new Set<string>();\n  private toolsUsed = new Set<string>();\n  private chainsUsed = new Set<number>();\n  private executionOrder: string[] = [];\n\n  validate(plan: Plan): ValidationResult {\n    this.issues = [];\n    this.nodeIds = new Set();\n    this.toolsUsed = new Set();\n    this.chainsUsed = new Set();\n    this.executionOrder = [];\n\n    // Pass 1: Structural\n    this.validateStructure(plan.root, 0);\n\n    // Pass 2: Temporal\n    this.validateTiming(plan);\n\n    // Pass 3: Financial (contradictions)\n    this.validateFinancial(plan.root);\n\n    // Pass 4: Tool validation\n    this.validateTools(plan.root);\n\n    // Pass 5: Safety\n    this.validateSafety(plan.root);\n\n    // Pass 6: Dependencies\n    this.validateDependencies(plan.root);\n\n    const hasErrors = this.issues.some(i => i.severity === 'error');\n\n    return {\n      valid: !hasErrors,\n      issues: this.issues,\n      estimatedGasEth: this.estimateGas(plan.root),\n      estimatedDurationMs: this.estimateDuration(plan.root),\n      toolsUsed: [...this.toolsUsed],\n      chainsUsed: [...this.chainsUsed],\n    };\n  }\n\n  // ─── Pass 1: Structural ─────────────────────────────────────────────\n\n  private validateStructure(node: PlanNode, depth: number): void {\n    // Depth check\n    if (depth > MAX_PLAN_DEPTH) {\n      this.addIssue('error', node.id, 'STRUCT_DEPTH', `Plan exceeds maximum nesting depth of ${MAX_PLAN_DEPTH}.`);\n      return;\n    }\n\n    // Unique ID check\n    if (this.nodeIds.has(node.id)) {\n      this.addIssue('error', node.id, 'STRUCT_DUP_ID', `Duplicate node ID: \"${node.id}\". Each step must have a unique ID.`);\n    }\n    this.nodeIds.add(node.id);\n\n    // Node count check\n    if (this.nodeIds.size > MAX_PLAN_NODES) {\n      this.addIssue('error', node.id, 'STRUCT_TOO_MANY', `Plan exceeds maximum of ${MAX_PLAN_NODES} nodes.`);\n      return;\n    }\n\n    // Missing label\n    if (!node.label || node.label.trim().length === 0) {\n      this.addIssue('warning', node.id, 'STRUCT_NO_LABEL', 'Node has no label. Labels help users understand the plan.');\n    }\n\n    // Recurse into children\n    switch (node.type) {\n      case 'action':\n        this.executionOrder.push(node.id);\n        break;\n      case 'sequence':\n        for (const step of node.steps) this.validateStructure(step, depth + 1);\n        break;\n      case 'parallel':\n        for (const step of node.steps) this.validateStructure(step, depth + 1);\n        break;\n      case 'if':\n        this.validateCondition(node.condition, node.id);\n        this.validateStructure(node.then, depth + 1);\n        if (node.else) this.validateStructure(node.else, depth + 1);\n        break;\n      case 'wait':\n        if (!node.until && !node.durationMs && !node.untilTime) {\n          this.addIssue('error', node.id, 'STRUCT_WAIT_EMPTY', 'Wait node has no condition, duration, or target time. It would wait forever.');\n        }\n        if (node.until && node.durationMs) {\n          this.addIssue('warning', node.id, 'STRUCT_WAIT_AMBIGUOUS', 'Wait has both a condition and a duration. The condition takes priority; duration is used as max wait.');\n        }\n        if (node.until) this.validateCondition(node.until, node.id);\n        break;\n      case 'loop':\n        if (!node.maxIterations || node.maxIterations <= 0) {\n          this.addIssue('error', node.id, CONTRADICTION_CODES.INFINITE_LOOP, 'Loop has no maxIterations or it is <= 0. This would loop forever.');\n        } else if (node.maxIterations > MAX_LOOP_ITERATIONS) {\n          this.addIssue('error', node.id, CONTRADICTION_CODES.INFINITE_LOOP, `Loop maxIterations (${node.maxIterations}) exceeds safety limit of ${MAX_LOOP_ITERATIONS}.`);\n        }\n        if (!node.exitWhen) {\n          this.addIssue('warning', node.id, 'LOOP_NO_EXIT', 'Loop has no exitWhen condition. It will run exactly maxIterations times.');\n        } else {\n          this.validateCondition(node.exitWhen, node.id);\n        }\n        this.validateStructure(node.body, depth + 1);\n        break;\n    }\n  }\n\n  private validateCondition(cond: Condition, nodeId: string): void {\n    if (cond.type === 'compare') {\n      this.validateValueRef(cond.left, nodeId);\n      this.validateValueRef(cond.right, nodeId);\n    } else if (cond.type === 'logic') {\n      if (cond.conditions.length === 0) {\n        this.addIssue('error', nodeId, 'COND_EMPTY', `Logic \"${cond.op}\" has no sub-conditions.`);\n      }\n      if (cond.op === 'not' && cond.conditions.length !== 1) {\n        this.addIssue('error', nodeId, 'COND_NOT_ARITY', '\"not\" must have exactly one sub-condition.');\n      }\n      for (const sub of cond.conditions) this.validateCondition(sub, nodeId);\n    }\n  }\n\n  private validateValueRef(ref: ValueRef | string | number | boolean, nodeId: string): void {\n    if (typeof ref !== 'object' || ref === null) return; // literal shorthand\n    if (ref.type === 'step_output') {\n      // Will be checked in dependency pass\n    } else if (ref.type === 'runtime') {\n      const validFns = new Set(['price', 'balance', 'gas_price', 'timestamp', 'block_number']);\n      if (!validFns.has(ref.fn)) {\n        this.addIssue('error', nodeId, 'REF_BAD_FN', `Unknown runtime function: \"${ref.fn}\".`);\n      }\n    }\n  }\n\n  // ─── Pass 2: Temporal ───────────────────────────────────────────────\n\n  private validateTiming(plan: Plan): void {\n    if (!plan.trigger) return;\n\n    const now = Date.now();\n\n    switch (plan.trigger.type) {\n      case 'time': {\n        const at = new Date(plan.trigger.at).getTime();\n        if (isNaN(at)) {\n          this.addIssue('error', null, CONTRADICTION_CODES.IMPOSSIBLE_TIMING, `Invalid trigger time: \"${plan.trigger.at}\". Use ISO 8601 format.`);\n        } else if (at <= now) {\n          this.addIssue('error', null, CONTRADICTION_CODES.IMPOSSIBLE_TIMING, `Trigger time \"${plan.trigger.at}\" is in the past.`);\n        } else if (at - now > 30 * 24 * 60 * 60 * 1000) {\n          this.addIssue('warning', null, 'TIME_FAR_FUTURE', 'Trigger is more than 30 days out. Consider whether conditions might change.');\n        }\n        break;\n      }\n      case 'interval': {\n        if (plan.trigger.everyMs < 30_000) {\n          this.addIssue('error', null, CONTRADICTION_CODES.IMPOSSIBLE_TIMING, 'Interval must be at least 30 seconds.');\n        }\n        if (plan.trigger.everyMs < 60_000) {\n          this.addIssue('warning', null, 'TIME_FAST_INTERVAL', 'Interval under 1 minute may cause excessive RPC calls and gas costs.');\n        }\n        if (plan.trigger.maxRuns && plan.trigger.maxRuns > 10_000) {\n          this.addIssue('warning', null, 'TIME_MANY_RUNS', `${plan.trigger.maxRuns} executions is a lot. Consider a reasonable bound.`);\n        }\n        break;\n      }\n      case 'condition': {\n        if (plan.trigger.pollIntervalMs && plan.trigger.pollIntervalMs < 10_000) {\n          this.addIssue('warning', null, 'TIME_FAST_POLL', 'Polling faster than 10s may cause rate limiting.');\n        }\n        if (!plan.trigger.expiresAfterMs) {\n          this.addIssue('warning', null, 'TIME_NO_EXPIRY', 'Condition trigger has no expiry. It will watch indefinitely. Consider setting expiresAfterMs.');\n        }\n        this.validateCondition(plan.trigger.when, 'trigger');\n        break;\n      }\n    }\n\n    // Check wait nodes for temporal sanity\n    this.validateWaitTiming(plan.root, now);\n  }\n\n  private validateWaitTiming(node: PlanNode, now: number): void {\n    if (node.type === 'wait') {\n      if (node.untilTime) {\n        const t = new Date(node.untilTime).getTime();\n        if (isNaN(t)) {\n          this.addIssue('error', node.id, CONTRADICTION_CODES.IMPOSSIBLE_TIMING, `Invalid wait time: \"${node.untilTime}\".`);\n        }\n        // Can't check if in past because plan might be scheduled for the future\n      }\n      if (node.maxWaitMs && node.maxWaitMs > 7 * 24 * 60 * 60 * 1000) {\n        this.addIssue('warning', node.id, 'WAIT_LONG', 'Wait timeout exceeds 7 days. Consider a shorter bound.');\n      }\n      if (!node.maxWaitMs && node.until) {\n        this.addIssue('warning', node.id, 'WAIT_NO_TIMEOUT', 'Wait on condition has no maxWaitMs. It could wait indefinitely. Default: 24h.');\n      }\n    }\n\n    // Recurse\n    if (node.type === 'sequence' || node.type === 'parallel') {\n      for (const s of node.steps) this.validateWaitTiming(s, now);\n    } else if (node.type === 'if') {\n      this.validateWaitTiming(node.then, now);\n      if (node.else) this.validateWaitTiming(node.else, now);\n    } else if (node.type === 'loop') {\n      this.validateWaitTiming(node.body, now);\n    }\n  }\n\n  // ─── Pass 3: Financial ──────────────────────────────────────────────\n\n  private validateFinancial(root: PlanNode): void {\n    const actions = this.collectActions(root);\n\n    // Extract all swap/transfer operations\n    const buys: Array<{ nodeId: string; token: string; amount?: string }> = [];\n    const sells: Array<{ nodeId: string; token: string; amount?: string }> = [];\n\n    for (const action of actions) {\n      const tool = action.tool;\n      const params = action.params;\n\n      if (tool === 'defi_swap') {\n        const tokenIn = this.resolveParamString(params.token_in ?? params.tokenIn);\n        const tokenOut = this.resolveParamString(params.token_out ?? params.tokenOut);\n        const amount = this.resolveParamString(params.amount);\n        if (tokenIn) sells.push({ nodeId: action.id, token: this.normalizeToken(tokenIn), amount });\n        if (tokenOut) buys.push({ nodeId: action.id, token: this.normalizeToken(tokenOut) });\n      } else if (tool === 'transfer') {\n        const token = this.resolveParamString(params.token);\n        const amount = this.resolveParamString(params.amount);\n        if (token) sells.push({ nodeId: action.id, token: this.normalizeToken(token), amount });\n      }\n    }\n\n    // Check: buying and selling the same token in the same plan\n    for (const buy of buys) {\n      for (const sell of sells) {\n        if (buy.token === sell.token && buy.nodeId !== sell.nodeId) {\n          // Only flag if they're not in the same swap (swapping A→B naturally sells A and buys B)\n          this.addIssue(\n            'warning', buy.nodeId,\n            CONTRADICTION_CODES.BUY_AND_SELL_SAME_TOKEN,\n            `Plan both buys and sells ${buy.token} (steps \"${buy.nodeId}\" and \"${sell.nodeId}\"). This may be intentional (arbitrage) or a mistake.`,\n          );\n        }\n      }\n    }\n\n    // Check: duplicate actions (same tool, same params)\n    for (let i = 0; i < actions.length; i++) {\n      for (let j = i + 1; j < actions.length; j++) {\n        if (actions[i]!.tool === actions[j]!.tool && this.paramsEqual(actions[i]!.params, actions[j]!.params)) {\n          this.addIssue(\n            'warning', actions[j]!.id,\n            CONTRADICTION_CODES.DUPLICATE_ACTION,\n            `Step \"${actions[j]!.id}\" appears to be a duplicate of \"${actions[i]!.id}\" (same tool and parameters).`,\n          );\n        }\n      }\n    }\n\n    // Check: multiple swaps spending the same token without checking balance in between\n    const spendsByToken = new Map<string, string[]>();\n    for (const sell of sells) {\n      const existing = spendsByToken.get(sell.token) ?? [];\n      existing.push(sell.nodeId);\n      spendsByToken.set(sell.token, existing);\n    }\n    for (const [token, nodeIds] of spendsByToken) {\n      if (nodeIds.length > 1) {\n        this.addIssue(\n          'warning', nodeIds[1]!,\n          CONTRADICTION_CODES.SPEND_MORE_THAN_BALANCE,\n          `Multiple steps spend ${token} (${nodeIds.join(', ')}). The second step may not have enough balance. Consider checking balance between steps.`,\n        );\n      }\n    }\n  }\n\n  // ─── Pass 4: Tool Validation ────────────────────────────────────────\n\n  private validateTools(node: PlanNode): void {\n    if (node.type === 'action') {\n      this.toolsUsed.add(node.tool);\n\n      if (!KNOWN_TOOLS.has(node.tool)) {\n        this.addIssue('warning', node.id, CONTRADICTION_CODES.MISSING_TOOL, `Unknown tool: \"${node.tool}\". It may be a custom or future tool.`);\n      }\n\n      // Check for write tools that might need confirmation\n      if (WRITE_TOOLS.has(node.tool) && !node.requireConfirmation) {\n        this.addIssue('info', node.id, 'TOOL_WRITE_NO_CONFIRM', `\"${node.tool}\" is a write operation. Consider setting requireConfirmation: true for safety.`);\n      }\n\n      // Extract chain info if available\n      const chainId = this.resolveParamNumber(node.params.chain_id ?? node.params.chainId);\n      if (chainId) {\n        this.chainsUsed.add(chainId);\n        if (![1, 8453, 42161, 10, 137].includes(chainId)) {\n          this.addIssue('warning', node.id, CONTRADICTION_CODES.UNSUPPORTED_CHAIN, `Chain ${chainId} is not in the standard supported set (Ethereum, Base, Arbitrum, Optimism, Polygon).`);\n        }\n      }\n\n      // Validate params have at least a value ref or literal\n      for (const [key, val] of Object.entries(node.params)) {\n        if (val === undefined || val === null) {\n          this.addIssue('warning', node.id, 'TOOL_NULL_PARAM', `Parameter \"${key}\" is null/undefined.`);\n        }\n      }\n    }\n\n    // Recurse\n    if (node.type === 'sequence' || node.type === 'parallel') {\n      for (const s of node.steps) this.validateTools(s);\n    } else if (node.type === 'if') {\n      this.validateTools(node.then);\n      if (node.else) this.validateTools(node.else);\n    } else if (node.type === 'loop') {\n      this.validateTools(node.body);\n    }\n  }\n\n  // ─── Pass 5: Safety ─────────────────────────────────────────────────\n\n  private validateSafety(root: PlanNode): void {\n    const actions = this.collectActions(root);\n\n    // Count write operations\n    const writeOps = actions.filter(a => WRITE_TOOLS.has(a.tool));\n    if (writeOps.length > 5) {\n      this.addIssue('warning', null, 'SAFETY_MANY_WRITES', `Plan has ${writeOps.length} write operations. Consider whether this is intentional.`);\n    }\n\n    // Check for high-value operations\n    for (const action of actions) {\n      if (action.tool === 'defi_swap' || action.tool === 'transfer') {\n        const amount = this.resolveParamString(action.params.amount);\n        if (amount) {\n          const num = parseFloat(amount);\n          if (!isNaN(num) && num > HIGH_VALUE_ETH_THRESHOLD) {\n            this.addIssue('warning', action.id, 'SAFETY_HIGH_VALUE', `Step \"${action.id}\" involves ${amount} which may be high value. Verify amounts carefully.`);\n          }\n        }\n      }\n    }\n\n    // Check total estimated gas\n    const gasEstimate = this.estimateGas(root);\n    if (gasEstimate > MAX_TOTAL_GAS_ETH) {\n      this.addIssue('warning', null, 'SAFETY_HIGH_GAS', `Estimated total gas: ${gasEstimate.toFixed(4)} ETH. This is above the ${MAX_TOTAL_GAS_ETH} ETH threshold.`);\n    }\n\n    // Parallel write operations are dangerous\n    this.checkParallelWrites(root);\n  }\n\n  private checkParallelWrites(node: PlanNode): void {\n    if (node.type === 'parallel') {\n      const writes = node.steps.filter(s =>\n        s.type === 'action' && WRITE_TOOLS.has(s.tool),\n      );\n      if (writes.length > 1) {\n        this.addIssue('error', node.id, 'SAFETY_PARALLEL_WRITES',\n          `Parallel node \"${node.id}\" contains ${writes.length} write operations. ` +\n          'Write operations must be sequential to prevent nonce conflicts and race conditions.');\n      }\n    }\n    // Recurse\n    if (node.type === 'sequence' || node.type === 'parallel') {\n      for (const s of node.steps) this.checkParallelWrites(s);\n    } else if (node.type === 'if') {\n      this.checkParallelWrites(node.then);\n      if (node.else) this.checkParallelWrites(node.else);\n    } else if (node.type === 'loop') {\n      this.checkParallelWrites(node.body);\n    }\n  }\n\n  // ─── Pass 6: Dependencies ──────────────────────────────────────────\n\n  private validateDependencies(root: PlanNode): void {\n    // Collect all step_output references and check they reference defined nodes\n    // that appear BEFORE the referencing node in execution order.\n    const definedBefore = new Set<string>();\n    this.walkDependencies(root, definedBefore);\n  }\n\n  private walkDependencies(node: PlanNode, definedBefore: Set<string>): void {\n    if (node.type === 'action') {\n      // Check all param refs\n      for (const [key, val] of Object.entries(node.params)) {\n        if (typeof val === 'object' && val !== null && 'type' in val && val.type === 'step_output') {\n          const ref = val as { type: 'step_output'; stepId: string; path: string };\n          if (!this.nodeIds.has(ref.stepId)) {\n            this.addIssue('error', node.id, CONTRADICTION_CODES.CIRCULAR_DEPENDENCY,\n              `Step \"${node.id}\" references output of \"${ref.stepId}\" which does not exist.`);\n          } else if (!definedBefore.has(ref.stepId)) {\n            this.addIssue('error', node.id, CONTRADICTION_CODES.CIRCULAR_DEPENDENCY,\n              `Step \"${node.id}\" references output of \"${ref.stepId}\" which hasn't executed yet at this point.`);\n          }\n        }\n      }\n      definedBefore.add(node.id);\n    } else if (node.type === 'sequence') {\n      for (const s of node.steps) this.walkDependencies(s, definedBefore);\n    } else if (node.type === 'parallel') {\n      // In parallel, no step can see any sibling's output\n      const beforeParallel = new Set(definedBefore);\n      for (const s of node.steps) {\n        this.walkDependencies(s, new Set(beforeParallel));\n      }\n      // After parallel, all steps are defined\n      for (const s of node.steps) this.collectNodeIds(s).forEach(id => definedBefore.add(id));\n    } else if (node.type === 'if') {\n      const beforeIf = new Set(definedBefore);\n      this.walkDependencies(node.then, new Set(beforeIf));\n      if (node.else) this.walkDependencies(node.else, new Set(beforeIf));\n      // After if, only nodes from both branches are guaranteed — conservative: add neither\n      // (outputs from conditional branches are unreliable as dependencies)\n    } else if (node.type === 'loop') {\n      this.walkDependencies(node.body, new Set(definedBefore));\n      // Loop body outputs are available after loop, but value is from last iteration\n      this.collectNodeIds(node.body).forEach(id => definedBefore.add(id));\n    } else if (node.type === 'wait') {\n      definedBefore.add(node.id);\n    }\n  }\n\n  private collectNodeIds(node: PlanNode): string[] {\n    const ids = [node.id];\n    if (node.type === 'sequence' || node.type === 'parallel') {\n      for (const s of node.steps) ids.push(...this.collectNodeIds(s));\n    } else if (node.type === 'if') {\n      ids.push(...this.collectNodeIds(node.then));\n      if (node.else) ids.push(...this.collectNodeIds(node.else));\n    } else if (node.type === 'loop') {\n      ids.push(...this.collectNodeIds(node.body));\n    }\n    return ids;\n  }\n\n  // ─── Gas Estimation ─────────────────────────────────────────────────\n\n  /** Rough gas estimate in ETH. Very approximate — real estimation requires RPC. */\n  private estimateGas(node: PlanNode): number {\n    const GAS_COSTS_ETH: Record<string, number> = {\n      defi_swap: 0.002,\n      transfer: 0.0005,\n      clawnch_launch: 0.01,\n      bridge: 0.003,\n      permit2: 0.0003,\n      liquidity: 0.005,\n      bankr_launch: 0.01,\n    };\n\n    if (node.type === 'action') {\n      return GAS_COSTS_ETH[node.tool] ?? 0;\n    } else if (node.type === 'sequence' || node.type === 'parallel') {\n      return node.steps.reduce((sum, s) => sum + this.estimateGas(s), 0);\n    } else if (node.type === 'if') {\n      // Estimate the more expensive branch\n      const thenGas = this.estimateGas(node.then);\n      const elseGas = node.else ? this.estimateGas(node.else) : 0;\n      return Math.max(thenGas, elseGas);\n    } else if (node.type === 'loop') {\n      // Estimate one iteration × maxIterations (worst case)\n      return this.estimateGas(node.body) * Math.min(node.maxIterations, 10);\n    }\n    return 0;\n  }\n\n  /** Rough duration estimate in ms. */\n  private estimateDuration(node: PlanNode): number {\n    const TOOL_DURATION_MS: Record<string, number> = {\n      defi_swap: 15_000,\n      transfer: 10_000,\n      clawnch_launch: 30_000,\n      bridge: 60_000,\n      defi_price: 3_000,\n      analytics: 5_000,\n      market_intel: 5_000,\n    };\n\n    if (node.type === 'action') {\n      return TOOL_DURATION_MS[node.tool] ?? 5_000;\n    } else if (node.type === 'sequence') {\n      return node.steps.reduce((sum, s) => sum + this.estimateDuration(s), 0);\n    } else if (node.type === 'parallel') {\n      return Math.max(...node.steps.map(s => this.estimateDuration(s)), 0);\n    } else if (node.type === 'if') {\n      return Math.max(this.estimateDuration(node.then), node.else ? this.estimateDuration(node.else) : 0);\n    } else if (node.type === 'wait') {\n      return node.durationMs ?? node.maxWaitMs ?? 60_000;\n    } else if (node.type === 'loop') {\n      return this.estimateDuration(node.body) * Math.min(node.maxIterations, 10) + (node.delayMs ?? 0) * Math.min(node.maxIterations, 10);\n    }\n    return 0;\n  }\n\n  // ─── Helpers ────────────────────────────────────────────────────────\n\n  private collectActions(node: PlanNode): ActionNode[] {\n    if (node.type === 'action') return [node];\n    if (node.type === 'sequence' || node.type === 'parallel') {\n      return node.steps.flatMap(s => this.collectActions(s));\n    }\n    if (node.type === 'if') {\n      const actions = this.collectActions(node.then);\n      if (node.else) actions.push(...this.collectActions(node.else));\n      return actions;\n    }\n    if (node.type === 'loop') return this.collectActions(node.body);\n    return [];\n  }\n\n  private resolveParamString(val: unknown): string | undefined {\n    if (typeof val === 'string') return val;\n    if (typeof val === 'object' && val !== null && 'type' in val) {\n      const ref = val as ValueRef;\n      if (ref.type === 'literal') return String(ref.value);\n    }\n    return undefined;\n  }\n\n  private resolveParamNumber(val: unknown): number | undefined {\n    const s = this.resolveParamString(val);\n    if (s === undefined) return undefined;\n    const n = Number(s);\n    return isNaN(n) ? undefined : n;\n  }\n\n  private normalizeToken(token: string): string {\n    return TOKEN_ALIASES[token] ?? TOKEN_ALIASES[token.toUpperCase()] ?? token.toUpperCase();\n  }\n\n  private paramsEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\n    const aKeys = Object.keys(a).sort();\n    const bKeys = Object.keys(b).sort();\n    if (aKeys.length !== bKeys.length) return false;\n    for (let i = 0; i < aKeys.length; i++) {\n      if (aKeys[i] !== bKeys[i]) return false;\n      const aVal = this.resolveParamString(a[aKeys[i]!]);\n      const bVal = this.resolveParamString(b[bKeys[i]!]);\n      if (aVal !== bVal) return false;\n    }\n    return true;\n  }\n\n  private addIssue(severity: IssueSeverity, nodeId: string | null, code: string, message: string): void {\n    this.issues.push({ severity, nodeId, code, message });\n  }\n}\n"],"mappings":"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"}