feat: routing policy dry-run (v0d, never applies)

New module cloud/routing_dryrun.py: dry-run a merged policy
document or an env mapping (file first, JSON overrides whole
tier entries, CLOUD_ROUTING_MODE overrides global mode only,
never explicit tier modes), reporting per-tier effective
model/mode/mode-source, dropped tiers with reasons, absent and
unknown tiers, and would_activate/would_shadow/would_off.
Dropped or unknown tiers block (CLI exit 1); warnings alone
(no version, fallback_models parsed but not applied, failed
file/JSON sources that the loader silently ignores) do not
block but are always printed. Model names are NOT validated
against a catalog (deliberately not whitelisted) and sample
counts are NOT checked here (that is the shadow report's job);
the CLI never writes env, files, or worker state.

Tests: test_routing_dryrun.py (8 tests).
This commit is contained in:
host committed 2026-11-04 18:01:44 +00:00
1 parent 38357c472d
commit 8fe4ad2f38
2 files changed
+451

No files matched your search

+282
View File
@@ -0,0 +1,282 @@
"""Routing policy dry-run (v0d): validate before applying, never apply.
A routing policy takes effect the moment a worker loads it from the
host env -- there is no CI gate for an env change. A typo in a tier
mode silently drops that tier, a bad model name is never checked
against a whitelist (models are not whitelisted by design), and a
policy file that fails to parse is silently ignored by the loader
(fail-closed to the worker default, but also silently). This module
surfaces all of that BEFORE the policy is applied, and it never
applies anything itself: it only reports what WOULD happen if the
given policy document were loaded.
What it reports, per tier (plan / goal / default):
* the effective model and mode, and whether the mode came from an
explicit tier mode or from the global mode,
* tiers that were dropped, and why (invalid tier mode, no model,
unrecognised entry) -- a dropped tier is a BLOCKER, not a warning
to skim past, because applying the policy would silently not route
that tier,
* tiers absent from the document (worker default, not routed),
* unknown tier names in the document (ignored by the parser),
* whether any tier would actually activate on next dispatch.
What it does NOT do, honestly:
* It does NOT validate model names against a provider or relay
catalog. Task models are deliberately not whitelisted in this
codebase (the relay catalog changes), so a model typo here is
reported as "unverified, not whitelisted" only if the caller
passes a known-model set; without one, model names are reported
as-is and the caller must check them against the relay catalog
themselves. This module never invents a catalog.
* It does NOT check shadow sample counts. That is the shadow
report's job (GET /routing-shadow); a dry-run that said "ready
to activate" without sample data would be fabrication.
* It does NOT change host env, worker state, or any file. The CLI
exits 1 when the policy is invalid or any tier was dropped or
unknown, so a deploy script can gate on it; warnings alone
(no version, fallback_models present) do not block, but are
always printed.
Loading order, mirrored from load_routing_policy in models.py:
file (CLOUD_ROUTING_POLICY_FILE) first, then JSON
(CLOUD_ROUTING_POLICY_JSON) overrides whole tier entries (not
per-field: a JSON tier entry replaces the file's tier entry
entirely), then CLOUD_ROUTING_MODE overrides the GLOBAL mode
only -- it never overrides an explicit tier mode. Failed file/JSON
sources, which the loader silently ignores, are reported here as
warnings instead of being swallowed.
"""
import argparse
import json
import os
import sys
try:
from cloud.models import ROUTING_MODES, ROUTING_TIERS
from cloud.models import parse_routing_policy
except ImportError: # run as a script from the repo root
sys.path.insert(0, os.path.join(
os.path.dirname(os.path.abspath(__file__)), ".."))
from cloud.models import ROUTING_MODES, ROUTING_TIERS
from cloud.models import parse_routing_policy
def _tier_dropped_reason(raw_entry):
if isinstance(raw_entry, dict):
if "mode" in raw_entry and \
raw_entry.get("mode") not in ROUTING_MODES:
return "invalid tier mode %r" % (raw_entry.get("mode"),)
return "no usable model"
if isinstance(raw_entry, str):
return "empty model" if not raw_entry.strip() else "unknown"
return "unrecognised tier entry (expected string or dict)"
def dry_run_policy_document(data, env_mode_override=None):
"""Dry-run one merged policy document (pure, no IO).
``data`` is the merged document as parse_routing_policy would
receive it. ``env_mode_override`` is the raw CLOUD_ROUTING_MODE
value (or None): a valid value overrides the global mode only,
an invalid value is ignored with a warning.
"""
warnings = []
tiers_report = {}
dropped = []
unknown = []
if not isinstance(data, dict):
return {
"valid": False, "blocked": True, "version": None,
"global_mode": None, "global_mode_source": None,
"tiers": tiers_report, "dropped_tiers": dropped,
"unknown_tiers": unknown,
"warnings": ["policy document is not an object; "
"the loader would ignore it entirely"],
"would_activate": [], "would_shadow": [], "would_off": [],
}
raw_tiers = data.get("tiers")
if isinstance(raw_tiers, dict):
for name in sorted(raw_tiers):
if name not in ROUTING_TIERS:
unknown.append(name)
warnings.append(
"unknown tier %r is ignored by the parser" % name)
policy = parse_routing_policy(data)
if policy is None:
warnings.append(
"policy is unusable (no usable tiers, or global mode "
"outside off/shadow/active); the loader would ignore it "
"entirely and workers would keep the worker default")
return {
"valid": False, "blocked": True, "version": None,
"global_mode": None, "global_mode_source": None,
"tiers": tiers_report, "dropped_tiers": dropped,
"unknown_tiers": unknown, "warnings": warnings,
"would_activate": [], "would_shadow": [], "would_off": [],
}
global_mode = policy.mode
global_source = "policy"
if env_mode_override:
if env_mode_override in ROUTING_MODES:
global_mode = env_mode_override
global_source = "env_override"
warnings.append(
"CLOUD_ROUTING_MODE overrides the global mode to %r, "
"but does NOT override explicit tier modes" %
env_mode_override)
else:
warnings.append(
"CLOUD_ROUTING_MODE %r is invalid and ignored; "
"the global mode from the policy stands" %
env_mode_override)
# Apply the env global override to the effective per-tier modes
# without mutating the parsed policy: a tier with an explicit
# mode keeps it, a tier without one follows the overridden global.
effective_policy_mode = global_mode
for tier in ROUTING_TIERS:
raw_entry = raw_tiers.get(tier) if isinstance(raw_tiers,
dict) else None
if tier not in policy.tiers:
if raw_entry is not None:
reason = _tier_dropped_reason(raw_entry)
dropped.append(tier)
warnings.append(
"tier %r was dropped: %s; applying this policy "
"would silently not route %r tasks" %
(tier, reason, tier))
tiers_report[tier] = {
"model": None, "mode": None,
"mode_source": None, "status": "dropped",
"dropped_reason": reason,
}
else:
tiers_report[tier] = {
"model": None, "mode": None,
"mode_source": None, "status": "absent",
"dropped_reason": None,
}
continue
if tier in policy.tier_modes:
mode = policy.tier_modes[tier]
mode_source = "tier_mode"
else:
mode = effective_policy_mode
mode_source = "global_mode"
status = "active" if mode == "active" else (
"shadow" if mode == "shadow" else "off")
tiers_report[tier] = {
"model": policy.tiers[tier], "mode": mode,
"mode_source": mode_source, "status": status,
"dropped_reason": None,
}
would_activate = [t for t in ROUTING_TIERS
if tiers_report[t]["status"] == "active"]
would_shadow = [t for t in ROUTING_TIERS
if tiers_report[t]["status"] == "shadow"]
would_off = [t for t in ROUTING_TIERS
if tiers_report[t]["status"] == "off"]
if policy.version is None:
warnings.append(
"no policy version: policy changes will be hard to "
"attribute in shadow reports (decisions record "
"policy_version)")
if data.get("fallback_models") is not None:
warnings.append(
"fallback_models in the policy are parsed but NOT "
"applied; only worker CLI --fallback-models enables a "
"real fallback retry")
if would_activate:
warnings.append(
"activation warning: tier(s) %s would actually route "
"tasks on next worker dispatch if this policy were "
"applied; this dry-run does not activate anything" %
", ".join(would_activate))
blocked = bool(dropped or unknown)
return {
"valid": True, "blocked": blocked,
"version": policy.version, "global_mode": global_mode,
"global_mode_source": global_source,
"tiers": tiers_report, "dropped_tiers": dropped,
"unknown_tiers": unknown, "warnings": warnings,
"would_activate": would_activate,
"would_shadow": would_shadow, "would_off": would_off,
}
def dry_run_from_env(env=None):
"""Dry-run from an env mapping, mirroring load_routing_policy.
Returns the report dict. File/JSON failures that the loader
silently ignores are reported as warnings here.
"""
env = env if env is not None else os.environ
warnings = []
merged = None
path = env.get("CLOUD_ROUTING_POLICY_FILE") or ""
if path:
try:
with open(path, encoding="utf-8") as fh:
merged = json.load(fh)
except (OSError, ValueError) as exc:
warnings.append(
"policy file %r could not be read/parsed (%s); "
"the loader would ignore it" % (path, exc))
merged = None
raw = env.get("CLOUD_ROUTING_POLICY_JSON") or ""
if raw:
try:
override = json.loads(raw)
except ValueError as exc:
warnings.append(
"CLOUD_ROUTING_POLICY_JSON could not be parsed "
"(%s); the loader would ignore it" % exc)
override = None
if isinstance(override, dict):
if not isinstance(merged, dict):
merged = override
else:
merged = dict(merged)
merged.update(override)
if isinstance(merged.get("tiers"), dict) and \
isinstance(override.get("tiers"), dict):
tiers = dict(merged["tiers"])
tiers.update(override["tiers"])
merged["tiers"] = tiers
report = dry_run_policy_document(
merged, env_mode_override=env.get("CLOUD_ROUTING_MODE") or None)
# Source-failure warnings belong before the document warnings,
# and they do not change blocked (a failed source alone is not
# a dropped tier; the document report already covers validity).
report["warnings"] = warnings + report["warnings"]
return report
def main(argv=None):
parser = argparse.ArgumentParser(
description="Dry-run a routing policy (never applies it).")
parser.add_argument("--policy-file", default=None,
help="Policy JSON file (same as "
"CLOUD_ROUTING_POLICY_FILE)")
parser.add_argument("--policy-json", default=None,
help="Policy JSON string (same as "
"CLOUD_ROUTING_POLICY_JSON)")
parser.add_argument("--mode", default=None,
help="Global mode override (same as "
"CLOUD_ROUTING_MODE)")
args = parser.parse_args(argv)
env = {}
if args.policy_file:
env["CLOUD_ROUTING_POLICY_FILE"] = args.policy_file
if args.policy_json:
env["CLOUD_ROUTING_POLICY_JSON"] = args.policy_json
if args.mode:
env["CLOUD_ROUTING_MODE"] = args.mode
report = dry_run_from_env(env)
print(json.dumps(report, indent=2, sort_keys=True))
return 1 if (not report["valid"] or report["blocked"]) else 0
if __name__ == "__main__":
raise SystemExit(main())
+169
View File
@@ -0,0 +1,169 @@
"""策略干跑校验 v0d 单测:有效档、丢档、未知档、环境覆盖、CLI。
运行(在仓库根目录下):
python3 -m unittest discover -s cloud/tests -p "test_routing_dryrun.py" -v
说明:纯函数部分用 plain dict,不碰库、不联网、不跑模型;
CLI 部分用子进程跑 `python3 -m cloud.routing_dryrun`,只读
传入的策略,不改任何文件或环境。关键断言:干跑本身不
激活任何东西(只报告 would_activate);丢档会阻塞退出码;
文件/JSON 合并是整档替换、不是按字段合并;环境模式只
覆盖全局、不覆盖显式档模式。
"""
import json
import os
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
try:
from cloud.routing_dryrun import dry_run_from_env
from cloud.routing_dryrun import dry_run_policy_document
except ImportError:
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from cloud.routing_dryrun import dry_run_from_env
from cloud.routing_dryrun import dry_run_policy_document
class DryRunDocumentTestCase(unittest.TestCase):
def test_plan_active_only(self):
report = dry_run_policy_document({
"version": "v1", "mode": "shadow",
"tiers": {
"plan": {"model": "gpt-6.1-sol", "mode": "active"},
"goal": "gpt-6.1-sol",
"default": "gpt-6.1-sol",
},
})
self.assertTrue(report["valid"])
self.assertFalse(report["blocked"])
self.assertEqual(report["tiers"]["plan"]["mode"], "active")
self.assertEqual(report["tiers"]["plan"]["mode_source"],
"tier_mode")
self.assertEqual(report["tiers"]["goal"]["mode"], "shadow")
self.assertEqual(report["tiers"]["goal"]["mode_source"],
"global_mode")
self.assertEqual(report["would_activate"], ["plan"])
def test_dropped_tier_blocks(self):
report = dry_run_policy_document({
"mode": "active",
"tiers": {
"plan": {"model": "gpt-6.1-sol", "mode": "activ"},
"default": "gpt-6.1-sol",
},
})
self.assertTrue(report["valid"])
self.assertTrue(report["blocked"])
self.assertEqual(report["dropped_tiers"], ["plan"])
self.assertEqual(report["tiers"]["plan"]["status"], "dropped")
self.assertEqual(report["tiers"]["default"]["status"], "active")
def test_unknown_tier_and_absent_tier(self):
report = dry_run_policy_document({
"mode": "shadow",
"tiers": {"plan": "gpt-6.1-sol", "weird": "gpt-6.1-sol"},
})
self.assertEqual(report["unknown_tiers"], ["weird"])
self.assertTrue(report["blocked"])
self.assertEqual(report["tiers"]["goal"]["status"], "absent")
self.assertIsNone(report["tiers"]["goal"]["model"])
def test_invalid_global_mode_and_no_version_warning(self):
report = dry_run_policy_document({
"mode": "bogus", "tiers": {"plan": "gpt-6.1-sol"},
})
self.assertFalse(report["valid"])
self.assertTrue(report["blocked"])
valid = dry_run_policy_document({
"mode": "shadow", "tiers": {"plan": "gpt-6.1-sol"},
"fallback_models": ["gpt-5.6-terra"],
})
self.assertTrue(any("no policy version" in w
for w in valid["warnings"]))
self.assertTrue(any("fallback_models" in w
for w in valid["warnings"]))
def test_env_mode_overrides_global_not_tier(self):
report = dry_run_policy_document({
"mode": "shadow",
"tiers": {
"plan": {"model": "gpt-6.1-sol", "mode": "active"},
"default": "gpt-6.1-sol",
},
}, env_mode_override="active")
self.assertEqual(report["global_mode"], "active")
self.assertEqual(report["global_mode_source"], "env_override")
self.assertEqual(report["tiers"]["plan"]["mode"], "active")
self.assertEqual(report["tiers"]["default"]["mode"], "active")
bad = dry_run_policy_document({
"mode": "shadow", "tiers": {"plan": "gpt-6.1-sol"},
}, env_mode_override="bogus")
self.assertEqual(bad["global_mode"], "shadow")
self.assertTrue(any("invalid and ignored" in w
for w in bad["warnings"]))
class DryRunEnvTestCase(unittest.TestCase):
def test_file_json_merge_replaces_whole_tier(self):
with tempfile.TemporaryDirectory() as tmpdir:
policy_path = os.path.join(tmpdir, "policy.json")
with open(policy_path, "w", encoding="utf-8") as fh:
json.dump({
"mode": "shadow",
"tiers": {
"plan": {"model": "gpt-6.1-sol",
"mode": "active"},
"default": "gpt-6.1-sol",
},
}, fh)
# JSON 覆盖 plan 为字符串:整档替换,档模式丢失,
# plan 回到全局 shadow,而不是字段合并保留 active。
report = dry_run_from_env({
"CLOUD_ROUTING_POLICY_FILE": policy_path,
"CLOUD_ROUTING_POLICY_JSON": json.dumps({
"tiers": {"plan": "gpt-6.1-sol"},
}),
})
self.assertEqual(report["tiers"]["plan"]["mode"], "shadow")
self.assertEqual(report["tiers"]["plan"]["mode_source"],
"global_mode")
def test_unreadable_file_is_warning_not_silent(self):
report = dry_run_from_env({
"CLOUD_ROUTING_POLICY_FILE": "/nonexistent/policy.json",
"CLOUD_ROUTING_POLICY_JSON": json.dumps({
"mode": "shadow", "tiers": {"plan": "gpt-6.1-sol"},
}),
})
self.assertTrue(report["valid"])
self.assertTrue(any("could not be read" in w
for w in report["warnings"]))
def test_cli_exit_codes(self):
repo_root = str(Path(__file__).resolve().parents[2])
good = subprocess.run(
[sys.executable, "-m", "cloud.routing_dryrun",
"--policy-json", json.dumps({
"mode": "shadow", "tiers": {"plan": "gpt-6.1-sol"},
})],
cwd=repo_root, capture_output=True, text=True, timeout=30)
self.assertEqual(good.returncode, 0, good.stderr)
report = json.loads(good.stdout)
self.assertTrue(report["valid"])
bad = subprocess.run(
[sys.executable, "-m", "cloud.routing_dryrun",
"--policy-json", json.dumps({
"mode": "active",
"tiers": {
"plan": {"model": "gpt-6.1-sol", "mode": "activ"},
"default": "gpt-6.1-sol",
},
})],
cwd=repo_root, capture_output=True, text=True, timeout=30)
self.assertEqual(bad.returncode, 1, bad.stdout)
self.assertEqual(json.loads(bad.stdout)["dropped_tiers"],
["plan"])