Files
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
60 KiB
JSON

{"repo": "anon987654321/pub4", "files": {"MASTER/lib/boot/runtime.rb": {"f06b5e44f99e63c2182b624b268f4fcb38a420bf": {"t": 1785745749.2544036, "n": 5074, "h": "da7acc5b59cf96a0", "c": "# frozen_string_literal: true\n\nmodule Master\n # Provider selection, model limits, and safe process defaults for Master.*.\n module MasterRuntime\n PROCESS_DEFAULTS = {\n \"MASTER_SAFE_MODE\" => \"1\", \"MASTER_BACKGROUND\" => \"0\", \"MASTER_AUTOFIX\" => \"0\",\n \"MASTER_WATCH\" => \"0\", \"MASTER_WATCHER\" => \"0\", \"MASTER_HEARTBEAT\" => \"0\", \"MASTER_DRIFT\" => \"0\",\n }.freeze\n # MASTER_LOOP selects one loop by mode name. The name->env mapping is the one\n # source in data/ops/process.yml (Ops::ProcessBudget.env_by_loop); \"fix\" is the\n # historical alias for the \"autofix\" loop. Kept explicit here because it is read\n # at early boot; test_master_loop pins it to process.yml so the two cannot drift.\n LOOP_FLAGS = {\n \"fix\" => \"MASTER_AUTOFIX\", \"watch\" => \"MASTER_WATCH\",\n \"watcher\" => \"MASTER_WATCHER\", \"heartbeat\" => \"MASTER_HEARTBEAT\",\n }.freeze\n\n def configure_providers!\n require_relative \"../io/bedrock_stub\"\n require \"ruby_llm\"\n require_relative \"../io/ruby_llm_patch\"\n RubyLLM.configure { |config| apply_api_keys(config) }\n Ground::KeyRotator.configure_current!\n [Ground::ModelQuota, Trace::CacheEfficiency].each(&:name)\n Trace::CacheEfficiency.load!\n end\n\n def apply_master_loop!\n mode = ENV[\"MASTER_LOOP\"].to_s.strip.downcase\n return if mode.empty?\n\n LOOP_FLAGS.values.each { |flag| ENV[flag] = \"0\" }\n ENV[LOOP_FLAGS[mode]] = \"1\" if LOOP_FLAGS.key?(mode)\n end\n\n def apply_process_defaults!\n apply_master_loop!\n return if ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] == \"1\"\n\n PROCESS_DEFAULTS.each { |key, value| ENV[key] ||= value }\n end\n\n def prepare_runtime!(unsafe: false)\n ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] = \"1\" if unsafe\n require_relative \"../ground/env_loader\"\n Ground::EnvLoader.load!\n apply_process_defaults!\n require_relative \"../ground/host_budget\"\n Ground::HostBudget.apply_defaults!\n install_process_guards!\n end\n\n def runtime_catalog = Ground::RuntimeCatalog\n\n def install_process_guards!\n require_relative \"../ops/loop_slot\"\n require_relative \"../ops/process_budget\"\n require_relative \"../ops/runtime_loop_guards\"\n Ops::LoopSlot.validate!\n Ops::ProcessBudget.validate_loop_slot!\n Ops::RuntimeLoopGuards.install!\n rescue LoadError => e\n warn(\"process_guards: #{e.message}\")\n end\n\n def provider_config(root: ROOT) = load_yaml(File.join(root, \"data\", \"providers.yml\"))\n\n def api_key_specs(root: ROOT)\n provider_config(root:).flat_map { |_name, config| provider_key_specs(config) }.compact\n end\n\n def api_key_present?(env_var, root: ROOT)\n spec = api_key_specs(root:).find { |_attr, candidate, _minimum| candidate == env_var }\n minimum = spec ? spec.last : MIN_API_KEY_LENGTH_HEURISTIC\n ENV[env_var].to_s.length >= minimum\n end\n\n def default_model\n return \"grok-4.3\" if api_key_present?(\"XAI_API_KEY\") && !api_key_present?(\"OPENROUTER_API_KEY\")\n return FREE_PRIMARY_MODEL if api_key_present?(\"OPENROUTER_API_KEY\")\n return \"deepseek-chat\" if api_key_present?(\"DEEPSEEK_API_KEY\")\n return \"gemini-2.5-flash\" if api_key_present?(\"GOOGLE_API_KEY\") || api_key_present?(\"GEMINI_API_KEY\")\n return \"web-chat:grok\" if keyless_llm_enabled?\n\n OPENROUTER_DEFAULT\n end\n\n def any_api_key_present?\n api_key_specs.any? { |_attr, env_var, minimum| ENV[env_var].to_s.length >= minimum }\n end\n\n def context_window(model = nil, root: ROOT)\n entry = provider_models(root:).values.find do |candidate|\n candidate.is_a?(Hash) && candidate[\"id\"].to_s == model.to_s\n end\n (entry&.fetch(\"context_window\", nil) || DEFAULT_CONTEXT_WINDOW).to_i\n end\n\n def provider_models(root: ROOT)\n load_yaml(File.join(root, \"data\", \"models.yml\")).fetch(\"model_defs\", {})\n end\n\n def keyless_llm_enabled?\n ENV[\"MASTER_KEYLESS\"].to_s != \"\" || ENV[\"MASTER_WEB_CHAT\"].to_s != \"\" || !any_api_key_present?\n end\n\n def no_api_key_message\n return keyless_message if keyless_llm_enabled?\n\n \"I'm not wired to any LLM yet. Set OPENROUTER_API_KEY or XAI_API_KEY in \" \\\n \"~/.config/master/env (or /etc/master.env on OpenBSD) and restart. \" \\\n \"Or enable keyless mode: MASTER_KEYLESS=1 (browser chat at zero cost).\"\n end\n\n private\n\n def apply_api_keys(config)\n api_key_specs.each do |attribute, env_var, minimum|\n key = ENV[env_var].to_s\n config.public_send(\"#{attribute}=\", key) if key.length >= minimum\n end\n end\n\n def provider_key_specs(config)\n return [] unless config.is_a?(Hash) && config[\"ruby_llm_key\"]\n\n minimum = config.fetch(\"min_key_length\", MIN_API_KEY_LENGTH_HEURISTIC).to_i\n Array(config[\"env\"]).map { |env_var| [config[\"ruby_llm_key\"].to_sym, env_var, minimum] }\n end\n\n def keyless_message\n \"No API keys configured — routing via free browser chat (web-chat:grok). \" \\\n \"Set OPENROUTER_API_KEY / XAI_API_KEY in ~/.config/master/env for API routing.\"\n end\n end\nend\n"}, "92e3c1b94888cc2c28acc23230e81dbfa60e1d30": {"t": 1785756134.454481, "n": 5074, "h": "da7acc5b59cf96a0", "c": "# frozen_string_literal: true\n\nmodule Master\n # Provider selection, model limits, and safe process defaults for Master.*.\n module MasterRuntime\n PROCESS_DEFAULTS = {\n \"MASTER_SAFE_MODE\" => \"1\", \"MASTER_BACKGROUND\" => \"0\", \"MASTER_AUTOFIX\" => \"0\",\n \"MASTER_WATCH\" => \"0\", \"MASTER_WATCHER\" => \"0\", \"MASTER_HEARTBEAT\" => \"0\", \"MASTER_DRIFT\" => \"0\",\n }.freeze\n # MASTER_LOOP selects one loop by mode name. The name->env mapping is the one\n # source in data/ops/process.yml (Ops::ProcessBudget.env_by_loop); \"fix\" is the\n # historical alias for the \"autofix\" loop. Kept explicit here because it is read\n # at early boot; test_master_loop pins it to process.yml so the two cannot drift.\n LOOP_FLAGS = {\n \"fix\" => \"MASTER_AUTOFIX\", \"watch\" => \"MASTER_WATCH\",\n \"watcher\" => \"MASTER_WATCHER\", \"heartbeat\" => \"MASTER_HEARTBEAT\",\n }.freeze\n\n def configure_providers!\n require_relative \"../io/bedrock_stub\"\n require \"ruby_llm\"\n require_relative \"../io/ruby_llm_patch\"\n RubyLLM.configure { |config| apply_api_keys(config) }\n Ground::KeyRotator.configure_current!\n [Ground::ModelQuota, Trace::CacheEfficiency].each(&:name)\n Trace::CacheEfficiency.load!\n end\n\n def apply_master_loop!\n mode = ENV[\"MASTER_LOOP\"].to_s.strip.downcase\n return if mode.empty?\n\n LOOP_FLAGS.values.each { |flag| ENV[flag] = \"0\" }\n ENV[LOOP_FLAGS[mode]] = \"1\" if LOOP_FLAGS.key?(mode)\n end\n\n def apply_process_defaults!\n apply_master_loop!\n return if ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] == \"1\"\n\n PROCESS_DEFAULTS.each { |key, value| ENV[key] ||= value }\n end\n\n def prepare_runtime!(unsafe: false)\n ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] = \"1\" if unsafe\n require_relative \"../ground/env_loader\"\n Ground::EnvLoader.load!\n apply_process_defaults!\n require_relative \"../ground/host_budget\"\n Ground::HostBudget.apply_defaults!\n install_process_guards!\n end\n\n def runtime_catalog = Ground::RuntimeCatalog\n\n def install_process_guards!\n require_relative \"../ops/loop_slot\"\n require_relative \"../ops/process_budget\"\n require_relative \"../ops/runtime_loop_guards\"\n Ops::LoopSlot.validate!\n Ops::ProcessBudget.validate_loop_slot!\n Ops::RuntimeLoopGuards.install!\n rescue LoadError => e\n warn(\"process_guards: #{e.message}\")\n end\n\n def provider_config(root: ROOT) = load_yaml(File.join(root, \"data\", \"providers.yml\"))\n\n def api_key_specs(root: ROOT)\n provider_config(root:).flat_map { |_name, config| provider_key_specs(config) }.compact\n end\n\n def api_key_present?(env_var, root: ROOT)\n spec = api_key_specs(root:).find { |_attr, candidate, _minimum| candidate == env_var }\n minimum = spec ? spec.last : MIN_API_KEY_LENGTH_HEURISTIC\n ENV[env_var].to_s.length >= minimum\n end\n\n def default_model\n return \"grok-4.3\" if api_key_present?(\"XAI_API_KEY\") && !api_key_present?(\"OPENROUTER_API_KEY\")\n return FREE_PRIMARY_MODEL if api_key_present?(\"OPENROUTER_API_KEY\")\n return \"deepseek-chat\" if api_key_present?(\"DEEPSEEK_API_KEY\")\n return \"gemini-2.5-flash\" if api_key_present?(\"GOOGLE_API_KEY\") || api_key_present?(\"GEMINI_API_KEY\")\n return \"web-chat:grok\" if keyless_llm_enabled?\n\n OPENROUTER_DEFAULT\n end\n\n def any_api_key_present?\n api_key_specs.any? { |_attr, env_var, minimum| ENV[env_var].to_s.length >= minimum }\n end\n\n def context_window(model = nil, root: ROOT)\n entry = provider_models(root:).values.find do |candidate|\n candidate.is_a?(Hash) && candidate[\"id\"].to_s == model.to_s\n end\n (entry&.fetch(\"context_window\", nil) || DEFAULT_CONTEXT_WINDOW).to_i\n end\n\n def provider_models(root: ROOT)\n load_yaml(File.join(root, \"data\", \"models.yml\")).fetch(\"model_defs\", {})\n end\n\n def keyless_llm_enabled?\n ENV[\"MASTER_KEYLESS\"].to_s != \"\" || ENV[\"MASTER_WEB_CHAT\"].to_s != \"\" || !any_api_key_present?\n end\n\n def no_api_key_message\n return keyless_message if keyless_llm_enabled?\n\n \"I'm not wired to any LLM yet. Set OPENROUTER_API_KEY or XAI_API_KEY in \" \\\n \"~/.config/master/env (or /etc/master.env on OpenBSD) and restart. \" \\\n \"Or enable keyless mode: MASTER_KEYLESS=1 (browser chat at zero cost).\"\n end\n\n private\n\n def apply_api_keys(config)\n api_key_specs.each do |attribute, env_var, minimum|\n key = ENV[env_var].to_s\n config.public_send(\"#{attribute}=\", key) if key.length >= minimum\n end\n end\n\n def provider_key_specs(config)\n return [] unless config.is_a?(Hash) && config[\"ruby_llm_key\"]\n\n minimum = config.fetch(\"min_key_length\", MIN_API_KEY_LENGTH_HEURISTIC).to_i\n Array(config[\"env\"]).map { |env_var| [config[\"ruby_llm_key\"].to_sym, env_var, minimum] }\n end\n\n def keyless_message\n \"No API keys configured — routing via free browser chat (web-chat:grok). \" \\\n \"Set OPENROUTER_API_KEY / XAI_API_KEY in ~/.config/master/env for API routing.\"\n end\n end\nend\n"}, "8c0a64fd6c1e2326f1f8be30e5ca1a11cb439b09": {"t": 1785756135.8560998, "n": 5072, "h": "ca5426cd1b879da1", "c": "# frozen_string_literal: true\n\nmodule Master\n # Provider selection, model limits, and safe process defaults for Master.*.\n module MasterRuntime\n PROCESS_DEFAULTS = {\n \"MASTER_SAFE_MODE\" => \"1\", \"MASTER_BACKGROUND\" => \"0\", \"MASTER_AUTOFIX\" => \"0\",\n \"MASTER_WATCH\" => \"0\", \"MASTER_WATCHER\" => \"0\", \"MASTER_HEARTBEAT\" => \"0\", \"MASTER_DRIFT\" => \"0\"\n }.freeze\n # MASTER_LOOP selects one loop by mode name. The name->env mapping is the one\n # source in data/ops/process.yml (Ops::ProcessBudget.env_by_loop); \"fix\" is the\n # historical alias for the \"autofix\" loop. Kept explicit here because it is read\n # at early boot; test_master_loop pins it to process.yml so the two cannot drift.\n LOOP_FLAGS = {\n \"fix\" => \"MASTER_AUTOFIX\", \"watch\" => \"MASTER_WATCH\",\n \"watcher\" => \"MASTER_WATCHER\", \"heartbeat\" => \"MASTER_HEARTBEAT\"\n }.freeze\n\n def configure_providers!\n require_relative \"../io/bedrock_stub\"\n require \"ruby_llm\"\n require_relative \"../io/ruby_llm_patch\"\n RubyLLM.configure { |config| apply_api_keys(config) }\n Ground::KeyRotator.configure_current!\n [Ground::ModelQuota, Trace::CacheEfficiency].each(&:name)\n Trace::CacheEfficiency.load!\n end\n\n def apply_master_loop!\n mode = ENV[\"MASTER_LOOP\"].to_s.strip.downcase\n return if mode.empty?\n\n LOOP_FLAGS.values.each { |flag| ENV[flag] = \"0\" }\n ENV[LOOP_FLAGS[mode]] = \"1\" if LOOP_FLAGS.key?(mode)\n end\n\n def apply_process_defaults!\n apply_master_loop!\n return if ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] == \"1\"\n\n PROCESS_DEFAULTS.each { |key, value| ENV[key] ||= value }\n end\n\n def prepare_runtime!(unsafe: false)\n ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] = \"1\" if unsafe\n require_relative \"../ground/env_loader\"\n Ground::EnvLoader.load!\n apply_process_defaults!\n require_relative \"../ground/host_budget\"\n Ground::HostBudget.apply_defaults!\n install_process_guards!\n end\n\n def runtime_catalog = Ground::RuntimeCatalog\n\n def install_process_guards!\n require_relative \"../ops/loop_slot\"\n require_relative \"../ops/process_budget\"\n require_relative \"../ops/runtime_loop_guards\"\n Ops::LoopSlot.validate!\n Ops::ProcessBudget.validate_loop_slot!\n Ops::RuntimeLoopGuards.install!\n rescue LoadError => e\n warn(\"process_guards: #{e.message}\")\n end\n\n def provider_config(root: ROOT) = load_yaml(File.join(root, \"data\", \"providers.yml\"))\n\n def api_key_specs(root: ROOT)\n provider_config(root:).flat_map { |_name, config| provider_key_specs(config) }.compact\n end\n\n def api_key_present?(env_var, root: ROOT)\n spec = api_key_specs(root:).find { |_attr, candidate, _minimum| candidate == env_var }\n minimum = spec ? spec.last : MIN_API_KEY_LENGTH_HEURISTIC\n ENV[env_var].to_s.length >= minimum\n end\n\n def default_model\n return \"grok-4.3\" if api_key_present?(\"XAI_API_KEY\") && !api_key_present?(\"OPENROUTER_API_KEY\")\n return FREE_PRIMARY_MODEL if api_key_present?(\"OPENROUTER_API_KEY\")\n return \"deepseek-chat\" if api_key_present?(\"DEEPSEEK_API_KEY\")\n return \"gemini-2.5-flash\" if api_key_present?(\"GOOGLE_API_KEY\") || api_key_present?(\"GEMINI_API_KEY\")\n return \"web-chat:grok\" if keyless_llm_enabled?\n\n OPENROUTER_DEFAULT\n end\n\n def any_api_key_present?\n api_key_specs.any? { |_attr, env_var, minimum| ENV[env_var].to_s.length >= minimum }\n end\n\n def context_window(model = nil, root: ROOT)\n entry = provider_models(root:).values.find do |candidate|\n candidate.is_a?(Hash) && candidate[\"id\"].to_s == model.to_s\n end\n (entry&.fetch(\"context_window\", nil) || DEFAULT_CONTEXT_WINDOW).to_i\n end\n\n def provider_models(root: ROOT)\n load_yaml(File.join(root, \"data\", \"models.yml\")).fetch(\"model_defs\", {})\n end\n\n def keyless_llm_enabled?\n ENV[\"MASTER_KEYLESS\"].to_s != \"\" || ENV[\"MASTER_WEB_CHAT\"].to_s != \"\" || !any_api_key_present?\n end\n\n def no_api_key_message\n return keyless_message if keyless_llm_enabled?\n\n \"I'm not wired to any LLM yet. Set OPENROUTER_API_KEY or XAI_API_KEY in \" \\\n \"~/.config/master/env (or /etc/master.env on OpenBSD) and restart. \" \\\n \"Or enable keyless mode: MASTER_KEYLESS=1 (browser chat at zero cost).\"\n end\n\n private\n\n def apply_api_keys(config)\n api_key_specs.each do |attribute, env_var, minimum|\n key = ENV[env_var].to_s\n config.public_send(\"#{attribute}=\", key) if key.length >= minimum\n end\n end\n\n def provider_key_specs(config)\n return [] unless config.is_a?(Hash) && config[\"ruby_llm_key\"]\n\n minimum = config.fetch(\"min_key_length\", MIN_API_KEY_LENGTH_HEURISTIC).to_i\n Array(config[\"env\"]).map { |env_var| [config[\"ruby_llm_key\"].to_sym, env_var, minimum] }\n end\n\n def keyless_message\n \"No API keys configured — routing via free browser chat (web-chat:grok). \" \\\n \"Set OPENROUTER_API_KEY / XAI_API_KEY in ~/.config/master/env for API routing.\"\n end\n end\nend\n"}, "693d2630d9b7ea062978b5f4eb81bf720412f9c8": {"t": 1785756137.021429, "n": 4998, "h": "0f2e0d9bfd8d5a91", "c": "# frozen_string_literal: true\n\nmodule Master\n # Provider selection, model limits, and safe process defaults for Master.*.\n module MasterRuntime\n PROCESS_DEFAULTS = {\n \"MASTER_SAFE_MODE\" => \"1\", \"MASTER_BACKGROUND\" => \"0\", \"MASTER_AUTOFIX\" => \"0\",\n \"MASTER_WATCH\" => \"0\", \"MASTER_WATCHER\" => \"0\", \"MASTER_HEARTBEAT\" => \"0\", \"MASTER_DRIFT\" => \"0\",\n }.freeze\n # MASTER_LOOP selects one loop by mode name. The name->env mapping is the one\n # source in data/ops/process.yml (Ops::ProcessBudget.env_by_loop); \"fix\" is the\n # historical alias for the \"autofix\" loop. Kept explicit here because it is read\n # at early boot; test_master_loop pins it to process.yml so the two cannot drift.\n LOOP_FLAGS = {\n \"fix\" => \"MASTER_AUTOFIX\", \"watch\" => \"MASTER_WATCH\",\n \"watcher\" => \"MASTER_WATCHER\", \"heartbeat\" => \"MASTER_HEARTBEAT\",\n }.freeze\n\n def configure_providers!\n require_relative \"../io/bedrock_stub\"\n require \"ruby_llm\"\n require_relative \"../io/ruby_llm_patch\"\n RubyLLM.configure { |config| apply_api_keys(config) }\n Ground::KeyRotator.configure_current!\n [Ground::ModelQuota, Trace::CacheEfficiency].each(&:name)\n Trace::CacheEfficiency.load!\n end\n\n def apply_master_loop!\n mode = ENV[\"MASTER_LOOP\"].to_s.strip.downcase\n return if mode.empty?\n\n LOOP_FLAGS.values.each { |flag| ENV[flag] = \"0\" }\n ENV[LOOP_FLAGS[mode]] = \"1\" if LOOP_FLAGS.key?(mode)\n end\n\n def apply_process_defaults!\n apply_master_loop!\n return if ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] == \"1\"\n\n PROCESS_DEFAULTS.each { |key, value| ENV[key] ||= value }\n end\n\n def prepare_runtime!(unsafe: false)\n ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] = \"1\" if unsafe\n apply_process_defaults!\n require_relative \"../ground/host_budget\"\n Ground::HostBudget.apply_defaults!\n install_process_guards!\n end\n\n def runtime_catalog = Ground::RuntimeCatalog\n\n def install_process_guards!\n require_relative \"../ops/loop_slot\"\n require_relative \"../ops/process_budget\"\n require_relative \"../ops/runtime_loop_guards\"\n Ops::LoopSlot.validate!\n Ops::ProcessBudget.validate_loop_slot!\n Ops::RuntimeLoopGuards.install!\n rescue LoadError => e\n warn(\"process_guards: #{e.message}\")\n end\n\n def provider_config(root: ROOT) = load_yaml(File.join(root, \"data\", \"providers.yml\"))\n\n def api_key_specs(root: ROOT)\n provider_config(root:).flat_map { |_name, config| provider_key_specs(config) }.compact\n end\n\n def api_key_present?(env_var, root: ROOT)\n spec = api_key_specs(root:).find { |_attr, candidate, _minimum| candidate == env_var }\n minimum = spec ? spec.last : MIN_API_KEY_LENGTH_HEURISTIC\n ENV[env_var].to_s.length >= minimum\n end\n\n def default_model\n return \"grok-4.3\" if api_key_present?(\"XAI_API_KEY\") && !api_key_present?(\"OPENROUTER_API_KEY\")\n return FREE_PRIMARY_MODEL if api_key_present?(\"OPENROUTER_API_KEY\")\n return \"deepseek-chat\" if api_key_present?(\"DEEPSEEK_API_KEY\")\n return \"gemini-2.5-flash\" if api_key_present?(\"GOOGLE_API_KEY\") || api_key_present?(\"GEMINI_API_KEY\")\n return \"web-chat:grok\" if keyless_llm_enabled?\n\n OPENROUTER_DEFAULT\n end\n\n def any_api_key_present?\n api_key_specs.any? { |_attr, env_var, minimum| ENV[env_var].to_s.length >= minimum }\n end\n\n def context_window(model = nil, root: ROOT)\n entry = provider_models(root:).values.find do |candidate|\n candidate.is_a?(Hash) && candidate[\"id\"].to_s == model.to_s\n end\n (entry&.fetch(\"context_window\", nil) || DEFAULT_CONTEXT_WINDOW).to_i\n end\n\n def provider_models(root: ROOT)\n load_yaml(File.join(root, \"data\", \"models.yml\")).fetch(\"model_defs\", {})\n end\n\n def keyless_llm_enabled?\n ENV[\"MASTER_KEYLESS\"].to_s != \"\" || ENV[\"MASTER_WEB_CHAT\"].to_s != \"\" || !any_api_key_present?\n end\n\n def no_api_key_message\n return keyless_message if keyless_llm_enabled?\n\n \"I'm not wired to any LLM yet. Set OPENROUTER_API_KEY or XAI_API_KEY in \" \\\n \"~/.config/master/env (or /etc/master.env on OpenBSD) and restart. \" \\\n \"Or enable keyless mode: MASTER_KEYLESS=1 (browser chat at zero cost).\"\n end\n\n private\n\n def apply_api_keys(config)\n api_key_specs.each do |attribute, env_var, minimum|\n key = ENV[env_var].to_s\n config.public_send(\"#{attribute}=\", key) if key.length >= minimum\n end\n end\n\n def provider_key_specs(config)\n return [] unless config.is_a?(Hash) && config[\"ruby_llm_key\"]\n\n minimum = config.fetch(\"min_key_length\", MIN_API_KEY_LENGTH_HEURISTIC).to_i\n Array(config[\"env\"]).map { |env_var| [config[\"ruby_llm_key\"].to_sym, env_var, minimum] }\n end\n\n def keyless_message\n \"No API keys configured — routing via free browser chat (web-chat:grok). \" \\\n \"Set OPENROUTER_API_KEY / XAI_API_KEY in ~/.config/master/env for API routing.\"\n end\n end\nend\n"}, "64dc6c26a341de7a4ba843c5a7b9a4dc662de702": {"t": 1785756138.2245884, "n": 5004, "h": "74c5c94024c00791", "c": "# frozen_string_literal: true\n\nmodule Master\n # Provider selection, model limits, and safe process defaults for Master.*.\n module MasterRuntime\n PROCESS_DEFAULTS = {\n \"MASTER_SAFE_MODE\" => \"1\", \"MASTER_BACKGROUND\" => \"0\", \"MASTER_AUTOFIX\" => \"0\",\n \"MASTER_WATCH\" => \"0\", \"MASTER_WATCHER\" => \"0\", \"MASTER_HEARTBEAT\" => \"0\", \"MASTER_DRIFT\" => \"0\",\n }.freeze\n # MASTER_LOOP selects one loop by mode name. The name->env mapping is the one\n # source in data/ops/process.yml (Ops::ProcessBudget.env_by_loop); \"fix\" is the\n # historical alias for the \"autofix\" loop. Kept explicit here because it is read\n # at early boot; test_master_loop pins it to process.yml so the two cannot drift.\n LOOP_FLAGS = {\n \"fix\" => \"MASTER_AUTOFIX\", \"watch\" => \"MASTER_WATCH\",\n \"watcher\" => \"MASTER_WATCHER\", \"heartbeat\" => \"MASTER_HEARTBEAT\",\n }.freeze\n\n def configure_providers!\n require_relative \"../reach/bedrock_stub\"\n require \"ruby_llm\"\n require_relative \"../reach/ruby_llm_patch\"\n RubyLLM.configure { |config| apply_api_keys(config) }\n Ground::KeyRotator.configure_current!\n [Ground::ModelQuota, Trace::CacheEfficiency].each(&:name)\n Trace::CacheEfficiency.load!\n end\n\n def apply_master_loop!\n mode = ENV[\"MASTER_LOOP\"].to_s.strip.downcase\n return if mode.empty?\n\n LOOP_FLAGS.values.each { |flag| ENV[flag] = \"0\" }\n ENV[LOOP_FLAGS[mode]] = \"1\" if LOOP_FLAGS.key?(mode)\n end\n\n def apply_process_defaults!\n apply_master_loop!\n return if ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] == \"1\"\n\n PROCESS_DEFAULTS.each { |key, value| ENV[key] ||= value }\n end\n\n def prepare_runtime!(unsafe: false)\n ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] = \"1\" if unsafe\n apply_process_defaults!\n require_relative \"../ground/host_budget\"\n Ground::HostBudget.apply_defaults!\n install_process_guards!\n end\n\n def runtime_catalog = Ground::RuntimeCatalog\n\n def install_process_guards!\n require_relative \"../ops/loop_slot\"\n require_relative \"../ops/process_budget\"\n require_relative \"../ops/runtime_loop_guards\"\n Ops::LoopSlot.validate!\n Ops::ProcessBudget.validate_loop_slot!\n Ops::RuntimeLoopGuards.install!\n rescue LoadError => e\n warn(\"process_guards: #{e.message}\")\n end\n\n def provider_config(root: ROOT) = load_yaml(File.join(root, \"data\", \"providers.yml\"))\n\n def api_key_specs(root: ROOT)\n provider_config(root:).flat_map { |_name, config| provider_key_specs(config) }.compact\n end\n\n def api_key_present?(env_var, root: ROOT)\n spec = api_key_specs(root:).find { |_attr, candidate, _minimum| candidate == env_var }\n minimum = spec ? spec.last : MIN_API_KEY_LENGTH_HEURISTIC\n ENV[env_var].to_s.length >= minimum\n end\n\n def default_model\n return \"grok-4.3\" if api_key_present?(\"XAI_API_KEY\") && !api_key_present?(\"OPENROUTER_API_KEY\")\n return FREE_PRIMARY_MODEL if api_key_present?(\"OPENROUTER_API_KEY\")\n return \"deepseek-chat\" if api_key_present?(\"DEEPSEEK_API_KEY\")\n return \"gemini-2.5-flash\" if api_key_present?(\"GOOGLE_API_KEY\") || api_key_present?(\"GEMINI_API_KEY\")\n return \"web-chat:grok\" if keyless_llm_enabled?\n\n OPENROUTER_DEFAULT\n end\n\n def any_api_key_present?\n api_key_specs.any? { |_attr, env_var, minimum| ENV[env_var].to_s.length >= minimum }\n end\n\n def context_window(model = nil, root: ROOT)\n entry = provider_models(root:).values.find do |candidate|\n candidate.is_a?(Hash) && candidate[\"id\"].to_s == model.to_s\n end\n (entry&.fetch(\"context_window\", nil) || DEFAULT_CONTEXT_WINDOW).to_i\n end\n\n def provider_models(root: ROOT)\n load_yaml(File.join(root, \"data\", \"models.yml\")).fetch(\"model_defs\", {})\n end\n\n def keyless_llm_enabled?\n ENV[\"MASTER_KEYLESS\"].to_s != \"\" || ENV[\"MASTER_WEB_CHAT\"].to_s != \"\" || !any_api_key_present?\n end\n\n def no_api_key_message\n return keyless_message if keyless_llm_enabled?\n\n \"I'm not wired to any LLM yet. Set OPENROUTER_API_KEY or XAI_API_KEY in \" \\\n \"~/.config/master/env (or /etc/master.env on OpenBSD) and restart. \" \\\n \"Or enable keyless mode: MASTER_KEYLESS=1 (browser chat at zero cost).\"\n end\n\n private\n\n def apply_api_keys(config)\n api_key_specs.each do |attribute, env_var, minimum|\n key = ENV[env_var].to_s\n config.public_send(\"#{attribute}=\", key) if key.length >= minimum\n end\n end\n\n def provider_key_specs(config)\n return [] unless config.is_a?(Hash) && config[\"ruby_llm_key\"]\n\n minimum = config.fetch(\"min_key_length\", MIN_API_KEY_LENGTH_HEURISTIC).to_i\n Array(config[\"env\"]).map { |env_var| [config[\"ruby_llm_key\"].to_sym, env_var, minimum] }\n end\n\n def keyless_message\n \"No API keys configured — routing via free browser chat (web-chat:grok). \" \\\n \"Set OPENROUTER_API_KEY / XAI_API_KEY in ~/.config/master/env for API routing.\"\n end\n end\nend\n"}, "c7f2d9905dc0de0cc9e8af03bbc3524ef3dde5b8": {"t": 1786067455.3563566, "n": 5074, "h": "da7acc5b59cf96a0", "c": "# frozen_string_literal: true\n\nmodule Master\n # Provider selection, model limits, and safe process defaults for Master.*.\n module MasterRuntime\n PROCESS_DEFAULTS = {\n \"MASTER_SAFE_MODE\" => \"1\", \"MASTER_BACKGROUND\" => \"0\", \"MASTER_AUTOFIX\" => \"0\",\n \"MASTER_WATCH\" => \"0\", \"MASTER_WATCHER\" => \"0\", \"MASTER_HEARTBEAT\" => \"0\", \"MASTER_DRIFT\" => \"0\",\n }.freeze\n # MASTER_LOOP selects one loop by mode name. The name->env mapping is the one\n # source in data/ops/process.yml (Ops::ProcessBudget.env_by_loop); \"fix\" is the\n # historical alias for the \"autofix\" loop. Kept explicit here because it is read\n # at early boot; test_master_loop pins it to process.yml so the two cannot drift.\n LOOP_FLAGS = {\n \"fix\" => \"MASTER_AUTOFIX\", \"watch\" => \"MASTER_WATCH\",\n \"watcher\" => \"MASTER_WATCHER\", \"heartbeat\" => \"MASTER_HEARTBEAT\",\n }.freeze\n\n def configure_providers!\n require_relative \"../io/bedrock_stub\"\n require \"ruby_llm\"\n require_relative \"../io/ruby_llm_patch\"\n RubyLLM.configure { |config| apply_api_keys(config) }\n Ground::KeyRotator.configure_current!\n [Ground::ModelQuota, Trace::CacheEfficiency].each(&:name)\n Trace::CacheEfficiency.load!\n end\n\n def apply_master_loop!\n mode = ENV[\"MASTER_LOOP\"].to_s.strip.downcase\n return if mode.empty?\n\n LOOP_FLAGS.values.each { |flag| ENV[flag] = \"0\" }\n ENV[LOOP_FLAGS[mode]] = \"1\" if LOOP_FLAGS.key?(mode)\n end\n\n def apply_process_defaults!\n apply_master_loop!\n return if ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] == \"1\"\n\n PROCESS_DEFAULTS.each { |key, value| ENV[key] ||= value }\n end\n\n def prepare_runtime!(unsafe: false)\n ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] = \"1\" if unsafe\n require_relative \"../ground/env_loader\"\n Ground::EnvLoader.load!\n apply_process_defaults!\n require_relative \"../ground/host_budget\"\n Ground::HostBudget.apply_defaults!\n install_process_guards!\n end\n\n def runtime_catalog = Ground::RuntimeCatalog\n\n def install_process_guards!\n require_relative \"../ops/loop_slot\"\n require_relative \"../ops/process_budget\"\n require_relative \"../ops/runtime_loop_guards\"\n Ops::LoopSlot.validate!\n Ops::ProcessBudget.validate_loop_slot!\n Ops::RuntimeLoopGuards.install!\n rescue LoadError => e\n warn(\"process_guards: #{e.message}\")\n end\n\n def provider_config(root: ROOT) = load_yaml(File.join(root, \"data\", \"providers.yml\"))\n\n def api_key_specs(root: ROOT)\n provider_config(root:).flat_map { |_name, config| provider_key_specs(config) }.compact\n end\n\n def api_key_present?(env_var, root: ROOT)\n spec = api_key_specs(root:).find { |_attr, candidate, _minimum| candidate == env_var }\n minimum = spec ? spec.last : MIN_API_KEY_LENGTH_HEURISTIC\n ENV[env_var].to_s.length >= minimum\n end\n\n def default_model\n return \"grok-4.3\" if api_key_present?(\"XAI_API_KEY\") && !api_key_present?(\"OPENROUTER_API_KEY\")\n return FREE_PRIMARY_MODEL if api_key_present?(\"OPENROUTER_API_KEY\")\n return \"deepseek-chat\" if api_key_present?(\"DEEPSEEK_API_KEY\")\n return \"gemini-2.5-flash\" if api_key_present?(\"GOOGLE_API_KEY\") || api_key_present?(\"GEMINI_API_KEY\")\n return \"web-chat:grok\" if keyless_llm_enabled?\n\n OPENROUTER_DEFAULT\n end\n\n def any_api_key_present?\n api_key_specs.any? { |_attr, env_var, minimum| ENV[env_var].to_s.length >= minimum }\n end\n\n def context_window(model = nil, root: ROOT)\n entry = provider_models(root:).values.find do |candidate|\n candidate.is_a?(Hash) && candidate[\"id\"].to_s == model.to_s\n end\n (entry&.fetch(\"context_window\", nil) || DEFAULT_CONTEXT_WINDOW).to_i\n end\n\n def provider_models(root: ROOT)\n load_yaml(File.join(root, \"data\", \"models.yml\")).fetch(\"model_defs\", {})\n end\n\n def keyless_llm_enabled?\n ENV[\"MASTER_KEYLESS\"].to_s != \"\" || ENV[\"MASTER_WEB_CHAT\"].to_s != \"\" || !any_api_key_present?\n end\n\n def no_api_key_message\n return keyless_message if keyless_llm_enabled?\n\n \"I'm not wired to any LLM yet. Set OPENROUTER_API_KEY or XAI_API_KEY in \" \\\n \"~/.config/master/env (or /etc/master.env on OpenBSD) and restart. \" \\\n \"Or enable keyless mode: MASTER_KEYLESS=1 (browser chat at zero cost).\"\n end\n\n private\n\n def apply_api_keys(config)\n api_key_specs.each do |attribute, env_var, minimum|\n key = ENV[env_var].to_s\n config.public_send(\"#{attribute}=\", key) if key.length >= minimum\n end\n end\n\n def provider_key_specs(config)\n return [] unless config.is_a?(Hash) && config[\"ruby_llm_key\"]\n\n minimum = config.fetch(\"min_key_length\", MIN_API_KEY_LENGTH_HEURISTIC).to_i\n Array(config[\"env\"]).map { |env_var| [config[\"ruby_llm_key\"].to_sym, env_var, minimum] }\n end\n\n def keyless_message\n \"No API keys configured — routing via free browser chat (web-chat:grok). \" \\\n \"Set OPENROUTER_API_KEY / XAI_API_KEY in ~/.config/master/env for API routing.\"\n end\n end\nend\n"}, "6300efc27f021e42d122a3c34ee3eaed3b238aff": {"t": 1786068311.1731005, "n": 5074, "h": "da7acc5b59cf96a0", "c": "# frozen_string_literal: true\n\nmodule Master\n # Provider selection, model limits, and safe process defaults for Master.*.\n module MasterRuntime\n PROCESS_DEFAULTS = {\n \"MASTER_SAFE_MODE\" => \"1\", \"MASTER_BACKGROUND\" => \"0\", \"MASTER_AUTOFIX\" => \"0\",\n \"MASTER_WATCH\" => \"0\", \"MASTER_WATCHER\" => \"0\", \"MASTER_HEARTBEAT\" => \"0\", \"MASTER_DRIFT\" => \"0\",\n }.freeze\n # MASTER_LOOP selects one loop by mode name. The name->env mapping is the one\n # source in data/ops/process.yml (Ops::ProcessBudget.env_by_loop); \"fix\" is the\n # historical alias for the \"autofix\" loop. Kept explicit here because it is read\n # at early boot; test_master_loop pins it to process.yml so the two cannot drift.\n LOOP_FLAGS = {\n \"fix\" => \"MASTER_AUTOFIX\", \"watch\" => \"MASTER_WATCH\",\n \"watcher\" => \"MASTER_WATCHER\", \"heartbeat\" => \"MASTER_HEARTBEAT\",\n }.freeze\n\n def configure_providers!\n require_relative \"../io/bedrock_stub\"\n require \"ruby_llm\"\n require_relative \"../io/ruby_llm_patch\"\n RubyLLM.configure { |config| apply_api_keys(config) }\n Ground::KeyRotator.configure_current!\n [Ground::ModelQuota, Trace::CacheEfficiency].each(&:name)\n Trace::CacheEfficiency.load!\n end\n\n def apply_master_loop!\n mode = ENV[\"MASTER_LOOP\"].to_s.strip.downcase\n return if mode.empty?\n\n LOOP_FLAGS.values.each { |flag| ENV[flag] = \"0\" }\n ENV[LOOP_FLAGS[mode]] = \"1\" if LOOP_FLAGS.key?(mode)\n end\n\n def apply_process_defaults!\n apply_master_loop!\n return if ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] == \"1\"\n\n PROCESS_DEFAULTS.each { |key, value| ENV[key] ||= value }\n end\n\n def prepare_runtime!(unsafe: false)\n ENV[\"MASTER_UNSAFE_PROCESS_DEFAULTS\"] = \"1\" if unsafe\n require_relative \"../ground/env_loader\"\n Ground::EnvLoader.load!\n apply_process_defaults!\n require_relative \"../ground/host_budget\"\n Ground::HostBudget.apply_defaults!\n install_process_guards!\n end\n\n def runtime_catalog = Ground::RuntimeCatalog\n\n def install_process_guards!\n require_relative \"../ops/loop_slot\"\n require_relative \"../ops/process_budget\"\n require_relative \"../ops/runtime_loop_guards\"\n Ops::LoopSlot.validate!\n Ops::ProcessBudget.validate_loop_slot!\n Ops::RuntimeLoopGuards.install!\n rescue LoadError => e\n warn(\"process_guards: #{e.message}\")\n end\n\n def provider_config(root: ROOT) = load_yaml(File.join(root, \"data\", \"providers.yml\"))\n\n def api_key_specs(root: ROOT)\n provider_config(root:).flat_map { |_name, config| provider_key_specs(config) }.compact\n end\n\n def api_key_present?(env_var, root: ROOT)\n spec = api_key_specs(root:).find { |_attr, candidate, _minimum| candidate == env_var }\n minimum = spec ? spec.last : MIN_API_KEY_LENGTH_HEURISTIC\n ENV[env_var].to_s.length >= minimum\n end\n\n def default_model\n return \"grok-4.3\" if api_key_present?(\"XAI_API_KEY\") && !api_key_present?(\"OPENROUTER_API_KEY\")\n return FREE_PRIMARY_MODEL if api_key_present?(\"OPENROUTER_API_KEY\")\n return \"deepseek-chat\" if api_key_present?(\"DEEPSEEK_API_KEY\")\n return \"gemini-2.5-flash\" if api_key_present?(\"GOOGLE_API_KEY\") || api_key_present?(\"GEMINI_API_KEY\")\n return \"web-chat:grok\" if keyless_llm_enabled?\n\n OPENROUTER_DEFAULT\n end\n\n def any_api_key_present?\n api_key_specs.any? { |_attr, env_var, minimum| ENV[env_var].to_s.length >= minimum }\n end\n\n def context_window(model = nil, root: ROOT)\n entry = provider_models(root:).values.find do |candidate|\n candidate.is_a?(Hash) && candidate[\"id\"].to_s == model.to_s\n end\n (entry&.fetch(\"context_window\", nil) || DEFAULT_CONTEXT_WINDOW).to_i\n end\n\n def provider_models(root: ROOT)\n load_yaml(File.join(root, \"data\", \"models.yml\")).fetch(\"model_defs\", {})\n end\n\n def keyless_llm_enabled?\n ENV[\"MASTER_KEYLESS\"].to_s != \"\" || ENV[\"MASTER_WEB_CHAT\"].to_s != \"\" || !any_api_key_present?\n end\n\n def no_api_key_message\n return keyless_message if keyless_llm_enabled?\n\n \"I'm not wired to any LLM yet. Set OPENROUTER_API_KEY or XAI_API_KEY in \" \\\n \"~/.config/master/env (or /etc/master.env on OpenBSD) and restart. \" \\\n \"Or enable keyless mode: MASTER_KEYLESS=1 (browser chat at zero cost).\"\n end\n\n private\n\n def apply_api_keys(config)\n api_key_specs.each do |attribute, env_var, minimum|\n key = ENV[env_var].to_s\n config.public_send(\"#{attribute}=\", key) if key.length >= minimum\n end\n end\n\n def provider_key_specs(config)\n return [] unless config.is_a?(Hash) && config[\"ruby_llm_key\"]\n\n minimum = config.fetch(\"min_key_length\", MIN_API_KEY_LENGTH_HEURISTIC).to_i\n Array(config[\"env\"]).map { |env_var| [config[\"ruby_llm_key\"].to_sym, env_var, minimum] }\n end\n\n def keyless_message\n \"No API keys configured — routing via free browser chat (web-chat:grok). \" \\\n \"Set OPENROUTER_API_KEY / XAI_API_KEY in ~/.config/master/env for API routing.\"\n end\n end\nend\n"}}, "MASTER/test/test_keyless_routing.rb": {"f06b5e44f99e63c2182b624b268f4fcb38a420bf": {"t": 1785745751.6121569, "n": 2736, "h": "7abcf202da59f365", "c": "# frozen_string_literal: true\n\nrequire_relative \"test_helper\"\n\nclass TestKeylessRouting < Minitest::Test\n class FakeConfig\n def initialize(model) = @model = model\n def model = @model\n end\n\n def setup\n @saved_env = %w[\n XAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY OPENAI_API_KEY\n DEEPSEEK_API_KEY GOOGLE_API_KEY GEMINI_API_KEY MISTRAL_API_KEY\n MASTER_KEYLESS MASTER_WEB_CHAT MASTER_NO_CLAUDE_CLI\n ].to_h { |key| [key, ENV[key]] }\n @saved_env.each_key { |key| ENV.delete(key) }\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n end\n\n def teardown\n @saved_env.each { |key, val| val.nil? ? ENV.delete(key) : ENV[key] = val }\n end\n\n def test_default_model_is_web_chat_grok_without_keys\n assert_equal \"web-chat:grok\", Master.default_model\n assert Master.keyless_llm_enabled?\n end\n\n def test_default_model_prefers_grok_api_with_xai_key\n ENV[\"XAI_API_KEY\"] = \"xai-\" + (\"a\" * 32)\n assert_equal \"grok-4.3\", Master.default_model\n refute Master.keyless_llm_enabled?\n end\n\n def test_router_injects_web_chat_models_when_keyless\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(\"web-chat:grok\"), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"web-chat:grok\", chain.first\n assert_includes chain, \"web-chat:chatgpt\"\n assert_includes chain, \"web-chat:kimi\"\n end\n\n def test_router_prefers_free_chain_when_openrouter_key_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"nvidia/nemotron-3-super-120b-a12b:free\", chain.first\n end\n\n def test_web_chat_disabled_when_keys_present_without_opt_in\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.web_chat_enabled?\n refute_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\n\n def test_web_chat_enabled_with_master_web_chat_even_when_keys_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n ENV[\"MASTER_WEB_CHAT\"] = \"1\"\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\nend\n"}, "693d2630d9b7ea062978b5f4eb81bf720412f9c8": {"t": 1785756135.5484467, "n": 2736, "h": "7abcf202da59f365", "c": "# frozen_string_literal: true\n\nrequire_relative \"test_helper\"\n\nclass TestKeylessRouting < Minitest::Test\n class FakeConfig\n def initialize(model) = @model = model\n def model = @model\n end\n\n def setup\n @saved_env = %w[\n XAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY OPENAI_API_KEY\n DEEPSEEK_API_KEY GOOGLE_API_KEY GEMINI_API_KEY MISTRAL_API_KEY\n MASTER_KEYLESS MASTER_WEB_CHAT MASTER_NO_CLAUDE_CLI\n ].to_h { |key| [key, ENV[key]] }\n @saved_env.each_key { |key| ENV.delete(key) }\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n end\n\n def teardown\n @saved_env.each { |key, val| val.nil? ? ENV.delete(key) : ENV[key] = val }\n end\n\n def test_default_model_is_web_chat_grok_without_keys\n assert_equal \"web-chat:grok\", Master.default_model\n assert Master.keyless_llm_enabled?\n end\n\n def test_default_model_prefers_grok_api_with_xai_key\n ENV[\"XAI_API_KEY\"] = \"xai-\" + (\"a\" * 32)\n assert_equal \"grok-4.3\", Master.default_model\n refute Master.keyless_llm_enabled?\n end\n\n def test_router_injects_web_chat_models_when_keyless\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(\"web-chat:grok\"), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"web-chat:grok\", chain.first\n assert_includes chain, \"web-chat:chatgpt\"\n assert_includes chain, \"web-chat:kimi\"\n end\n\n def test_router_prefers_free_chain_when_openrouter_key_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"nvidia/nemotron-3-super-120b-a12b:free\", chain.first\n end\n\n def test_web_chat_disabled_when_keys_present_without_opt_in\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.web_chat_enabled?\n refute_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\n\n def test_web_chat_enabled_with_master_web_chat_even_when_keys_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n ENV[\"MASTER_WEB_CHAT\"] = \"1\"\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\nend\n"}, "f90c6aa215fd1fcb5f866dc71700790502710c96": {"t": 1785756136.840369, "n": 2736, "h": "46584e28d2a49c55", "c": "# frozen_string_literal: true\n\nrequire_relative \"test_helper\"\n\nclass TestKeylessRouting < Minitest::Test\n class FakeConfig\n def initialize(model) = @model = model\n def model = @model\n end\n\n def setup\n @saved_env = %w[\n XAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY OPENAI_API_KEY\n DEEPSEEK_API_KEY GOOGLE_API_KEY GEMINI_API_KEY MISTRAL_API_KEY\n MASTER_KEYLESS MASTER_WEB_CHAT MASTER_NO_CLAUDE_CLI\n ].to_h { |key| [key, ENV[key]] }\n @saved_env.each_key { |key| ENV.delete(key) }\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n end\n\n def teardown\n @saved_env.each { |key, val| val.nil? ? ENV.delete(key) : ENV[key] = val }\n end\n\n def test_default_model_is_web_chat_grok_without_keys\n assert_equal \"web-chat:grok\", Master.default_model\n assert Master.keyless_llm_enabled?\n end\n\n def test_default_model_prefers_grok_api_with_xai_key\n ENV[\"XAI_API_KEY\"] = \"xai-\" + (\"a\" * 32)\n assert_equal \"grok-4.3\", Master.default_model\n refute Master.keyless_llm_enabled?\n end\n\n def test_router_injects_web_chat_models_when_keyless\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"web-chat:grok\"), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"web-chat:grok\", chain.first\n assert_includes chain, \"web-chat:chatgpt\"\n assert_includes chain, \"web-chat:kimi\"\n end\n\n def test_router_prefers_free_chain_when_openrouter_key_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"nvidia/nemotron-3-super-120b-a12b:free\", chain.first\n end\n\n def test_web_chat_disabled_when_keys_present_without_opt_in\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.web_chat_enabled?\n refute_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\n\n def test_web_chat_enabled_with_master_web_chat_even_when_keys_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n ENV[\"MASTER_WEB_CHAT\"] = \"1\"\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\nend\n"}, "7f5a46da9edfff9aa23705b15fd4b2d85fa4ddbb": {"t": 1785756138.1504517, "n": 2698, "h": "8ac7d70117d9258d", "c": "# frozen_string_literal: true\n\nrequire_relative \"test_helper\"\n\nclass TestKeylessRouting < Minitest::Test\n class FakeConfig\n def initialize(model) = @model = model\n def model = @model\n end\n\n def setup\n @saved_env = %w[\n XAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY OPENAI_API_KEY\n DEEPSEEK_API_KEY GOOGLE_API_KEY GEMINI_API_KEY MISTRAL_API_KEY\n MASTER_KEYLESS MASTER_WEB_CHAT MASTER_NO_CLAUDE_CLI\n ].to_h { |key| [key, ENV[key]] }\n @saved_env.each_key { |key| ENV.delete(key) }\n end\n\n def teardown\n @saved_env.each { |key, val| val.nil? ? ENV.delete(key) : ENV[key] = val }\n end\n\n def test_default_model_is_web_chat_grok_without_keys\n assert_equal \"web-chat:grok\", Master.default_model\n assert Master.keyless_llm_enabled?\n end\n\n def test_default_model_prefers_grok_api_with_xai_key\n ENV[\"XAI_API_KEY\"] = \"xai-\" + (\"a\" * 32)\n assert_equal \"grok-4.3\", Master.default_model\n refute Master.keyless_llm_enabled?\n end\n\n def test_router_injects_web_chat_models_when_keyless\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"web-chat:grok\"), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"web-chat:grok\", chain.first\n assert_includes chain, \"web-chat:chatgpt\"\n assert_includes chain, \"web-chat:kimi\"\n end\n\n def test_router_prefers_free_chain_when_openrouter_key_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"nvidia/nemotron-3-super-120b-a12b:free\", chain.first\n end\n\n def test_web_chat_disabled_when_keys_present_without_opt_in\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.web_chat_enabled?\n refute_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\n\n def test_web_chat_enabled_with_master_web_chat_even_when_keys_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n ENV[\"MASTER_WEB_CHAT\"] = \"1\"\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\nend\n"}, "234c72ab152b590ea7db4c3f0a3fc3609b344b7a": {"t": 1785756139.4098725, "n": 2658, "h": "371f91e0a72c286d", "c": "# frozen_string_literal: true\n\nrequire_relative \"test_helper\"\n\nclass TestKeylessRouting < Minitest::Test\n class FakeConfig\n def initialize(model) = @model = model\n def model = @model\n end\n\n def setup\n @saved_env = %w[\n XAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY OPENAI_API_KEY\n DEEPSEEK_API_KEY GOOGLE_API_KEY GEMINI_API_KEY MISTRAL_API_KEY\n MASTER_KEYLESS MASTER_WEB_CHAT MASTER_NO_CLAUDE_CLI\n ].to_h { |key| [key, ENV[key]] }\n @saved_env.each_key { |key| ENV.delete(key) }\n end\n\n def teardown\n @saved_env.each { |key, val| val.nil? ? ENV.delete(key) : ENV[key] = val }\n end\n\n def test_default_model_is_web_chat_grok_without_keys\n assert_equal \"web-chat:grok\", Master.default_model\n assert Master.keyless_llm_enabled?\n end\n\n def test_default_model_prefers_grok_api_with_xai_key\n ENV[\"XAI_API_KEY\"] = \"xai-\" + (\"a\" * 32)\n assert_equal \"x-ai/grok-4-fast\", Master.default_model\n refute Master.keyless_llm_enabled?\n end\n\n def test_router_injects_web_chat_models_when_keyless\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"web-chat:grok\"), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"web-chat:grok\", chain.first\n assert_includes chain, \"web-chat:chatgpt\"\n assert_includes chain, \"web-chat:kimi\"\n end\n\n def test_router_prefers_grok_api_when_openrouter_key_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"x-ai/grok-4-fast\"), root: Master::ROOT,\n )\n refute router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"x-ai/grok-4-fast\", chain.first\n end\n\n def test_web_chat_disabled_when_keys_present_without_opt_in\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"x-ai/grok-4-fast\"), root: Master::ROOT,\n )\n refute router.web_chat_enabled?\n refute_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\n\n def test_web_chat_enabled_with_master_web_chat_even_when_keys_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n ENV[\"MASTER_WEB_CHAT\"] = \"1\"\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"x-ai/grok-4-fast\"), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\nend\n"}, "59f66f32ec9baeae7d38ec8a2e22493d3da37622": {"t": 1785756140.7030756, "n": 2629, "h": "6b4603bc45c2bbe5", "c": "# frozen_string_literal: true\n\nrequire_relative \"test_helper\"\n\nclass TestKeylessRouting < Minitest::Test\n class FakeConfig\n def initialize(model) = @model = model\n def model = @model\n end\n\n def setup\n @saved_env = %w[\n XAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY OPENAI_API_KEY\n DEEPSEEK_API_KEY GEMINI_API_KEY MISTRAL_API_KEY\n MASTER_KEYLESS MASTER_WEB_CHAT MASTER_NO_CLAUDE_CLI\n ].to_h { |key| [key, ENV[key]] }\n @saved_env.each_key { |key| ENV.delete(key) }\n end\n\n def teardown\n @saved_env.each { |key, val| val.nil? ? ENV.delete(key) : ENV[key] = val }\n end\n\n def test_default_model_is_web_chat_grok_without_keys\n assert_equal \"web-chat:grok\", Master.default_model\n assert Master.keyless_llm_enabled?\n end\n\n def test_default_model_prefers_grok_api_with_xai_key\n ENV[\"XAI_API_KEY\"] = \"xai-\" + (\"a\" * 32)\n assert_equal \"x-ai/grok-4-fast\", Master.default_model\n refute Master.keyless_llm_enabled?\n end\n\n def test_router_injects_web_chat_models_when_keyless\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"web-chat:grok\"), root: Master::ROOT\n )\n assert router.web_chat_enabled?\n assert router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"web-chat:grok\", chain.first\n assert_includes chain, \"web-chat:chatgpt\"\n assert_includes chain, \"web-chat:kimi\"\n end\n\n def test_router_prefers_grok_api_when_openrouter_key_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-\" + (\"a\" * 32)\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"x-ai/grok-4-fast\"), root: Master::ROOT\n )\n refute router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"x-ai/grok-4-fast\", chain.first\n end\n\n def test_web_chat_disabled_when_keys_present_without_opt_in\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-\" + (\"a\" * 32)\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"x-ai/grok-4-fast\"), root: Master::ROOT\n )\n refute router.web_chat_enabled?\n refute_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\n\n def test_web_chat_enabled_with_master_web_chat_even_when_keys_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-\" + (\"a\" * 32)\n ENV[\"MASTER_WEB_CHAT\"] = \"1\"\n router = Master::Now::Routing::ModelRouter.new(\n config: FakeConfig.new(\"x-ai/grok-4-fast\"), root: Master::ROOT\n )\n assert router.web_chat_enabled?\n assert_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\nend"}, "c7f2d9905dc0de0cc9e8af03bbc3524ef3dde5b8": {"t": 1786067456.2047315, "n": 2736, "h": "7abcf202da59f365", "c": "# frozen_string_literal: true\n\nrequire_relative \"test_helper\"\n\nclass TestKeylessRouting < Minitest::Test\n class FakeConfig\n def initialize(model) = @model = model\n def model = @model\n end\n\n def setup\n @saved_env = %w[\n XAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY OPENAI_API_KEY\n DEEPSEEK_API_KEY GOOGLE_API_KEY GEMINI_API_KEY MISTRAL_API_KEY\n MASTER_KEYLESS MASTER_WEB_CHAT MASTER_NO_CLAUDE_CLI\n ].to_h { |key| [key, ENV[key]] }\n @saved_env.each_key { |key| ENV.delete(key) }\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n end\n\n def teardown\n @saved_env.each { |key, val| val.nil? ? ENV.delete(key) : ENV[key] = val }\n end\n\n def test_default_model_is_web_chat_grok_without_keys\n assert_equal \"web-chat:grok\", Master.default_model\n assert Master.keyless_llm_enabled?\n end\n\n def test_default_model_prefers_grok_api_with_xai_key\n ENV[\"XAI_API_KEY\"] = \"xai-\" + (\"a\" * 32)\n assert_equal \"grok-4.3\", Master.default_model\n refute Master.keyless_llm_enabled?\n end\n\n def test_router_injects_web_chat_models_when_keyless\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(\"web-chat:grok\"), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"web-chat:grok\", chain.first\n assert_includes chain, \"web-chat:chatgpt\"\n assert_includes chain, \"web-chat:kimi\"\n end\n\n def test_router_prefers_free_chain_when_openrouter_key_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"nvidia/nemotron-3-super-120b-a12b:free\", chain.first\n end\n\n def test_web_chat_disabled_when_keys_present_without_opt_in\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.web_chat_enabled?\n refute_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\n\n def test_web_chat_enabled_with_master_web_chat_even_when_keys_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n ENV[\"MASTER_WEB_CHAT\"] = \"1\"\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\nend\n"}, "6300efc27f021e42d122a3c34ee3eaed3b238aff": {"t": 1786068311.765565, "n": 2736, "h": "7abcf202da59f365", "c": "# frozen_string_literal: true\n\nrequire_relative \"test_helper\"\n\nclass TestKeylessRouting < Minitest::Test\n class FakeConfig\n def initialize(model) = @model = model\n def model = @model\n end\n\n def setup\n @saved_env = %w[\n XAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY OPENAI_API_KEY\n DEEPSEEK_API_KEY GOOGLE_API_KEY GEMINI_API_KEY MISTRAL_API_KEY\n MASTER_KEYLESS MASTER_WEB_CHAT MASTER_NO_CLAUDE_CLI\n ].to_h { |key| [key, ENV[key]] }\n @saved_env.each_key { |key| ENV.delete(key) }\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n end\n\n def teardown\n @saved_env.each { |key, val| val.nil? ? ENV.delete(key) : ENV[key] = val }\n end\n\n def test_default_model_is_web_chat_grok_without_keys\n assert_equal \"web-chat:grok\", Master.default_model\n assert Master.keyless_llm_enabled?\n end\n\n def test_default_model_prefers_grok_api_with_xai_key\n ENV[\"XAI_API_KEY\"] = \"xai-\" + (\"a\" * 32)\n assert_equal \"grok-4.3\", Master.default_model\n refute Master.keyless_llm_enabled?\n end\n\n def test_router_injects_web_chat_models_when_keyless\n ENV[\"MASTER_NO_CLAUDE_CLI\"] = \"1\"\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(\"web-chat:grok\"), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"web-chat:grok\", chain.first\n assert_includes chain, \"web-chat:chatgpt\"\n assert_includes chain, \"web-chat:kimi\"\n end\n\n def test_router_prefers_free_chain_when_openrouter_key_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.keyless_mode?\n chain = router.fallback_chain(task_type: :exploration)\n assert_equal \"nvidia/nemotron-3-super-120b-a12b:free\", chain.first\n end\n\n def test_web_chat_disabled_when_keys_present_without_opt_in\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n refute router.web_chat_enabled?\n refute_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\n\n def test_web_chat_enabled_with_master_web_chat_even_when_keys_present\n ENV[\"OPENROUTER_API_KEY\"] = \"sk-or-v1-\" + (\"a\" * 64)\n ENV[\"MASTER_WEB_CHAT\"] = \"1\"\n router = Master::CLI::Routing::ModelRouter.new(\n config: FakeConfig.new(Master::FREE_PRIMARY_MODEL), root: Master::ROOT,\n )\n assert router.web_chat_enabled?\n assert_includes router.fallback_chain(task_type: :exploration), \"web-chat:grok\"\n end\nend\n"}}}}