fix: second-audit gate findings (B1, I1-I8, M1-M10)

B1: gateway capability check now triggers on walking the sub2api
gateway, not on the gateway having filled a model; task-level
explicit models are audited (worker_capability_gateway_explicit)
but never blocked, preserving explicit priority; gateway-default
models still fail-fast under active.
I1: dry-run adds a gateway-model section, sourced only from
CLOUD_SUB2API_DEFAULT_MODEL (never queries the relay); an active
tier whose requires the gateway model fails or cannot verify
blocks, shadow only warns.
I2: shadow review gate now counts completed samples
(completed >= 20), same basis for sample_shortfall; the endpoint
attaches per-tier capability status (read-only policy load) and
flags capability-failing tiers in the recommendation.
I3: configured-but-broken routing policy logs a warning in
load_routing_policy (unconfigured stays silent); the worker sets
routing_policy_load_failed and audits
worker_routing_policy_load_failed per task.
I4: resume preamble wraps prior output/error as data with an
explicit do-not-execute constraint; position verified in run_one
(tree -> preamble -> project -> original) and the docs corrected
from the false 'closest to the original prompt' claim.
I5: decided model is written back with a CAS UPDATE
(model IS NULL OR model=''), so later attempts reuse it;
explicit models are never overwritten.
I6: agent_* columns added to worker._ensure_result_columns and
db.init_postgres_schema backfill; migrations backfills them for
tasks before insert (sender_task_id pattern); column-level tests
for agent_tool_approvals and task_attempts.
I7: coordinator requeue adds AND status=<snapshot> (rowcount 0
skips requeue/audit) and filters paused_by_user / user_cancel /
user_pause children, which are never revived or cleared.
I8: explicit-model tasks (including coordinator children that
inherited a parent model) audit a source=explicit worker_routing
row; evaluate_shadow counts it as per-tier explicit_n only,
never routed_n, never a dedup slot.
M1/M2/M3/M5/M6/M8/M10: dedup slot moved after tier validation,
shadow sort doc fixed, truncated recommendation notes truncation,
seed cleanup on gateway/quota/goal-cap early returns, tools-only
coordinator definitions rejected, preamble goal branch marked
effectively unreachable, DESIGN.md drift corrected (outside repo).
M4/M7/M9: documentation/new-field only (pass_rate_fully_measured,
whitespace-model shadow-drop note, bound-note race note); old
field semantics unchanged.
This commit is contained in:
host committed 2026-11-04 18:02:21 +00:00
1 parent f9a77577c5
commit 621c08d10f
13 files changed
+907 -44

No files matched your search

+38 -4
View File
@@ -17,8 +17,11 @@ worker-default chain instead of failing the task.
"""
import json
import logging
import os
_logger = logging.getLogger("cloud.models")
FALLBACKABLE = {404, 429, 500, 502, 503, 504, "timeout"}
@@ -277,6 +280,12 @@ def classify_task(task) -> str:
def _clean_model_name(value):
# Audit fix 3(M7,文档级):只 strip、不校验字符集。
# 含空白的模型名仍会原样进审计 detail,而影子审计
# 格式是空白分隔,整行解析失败即无声丢样本(不报错、
# 不计数)。这里不加字符集校验——那会改变模型名接受
# 语义、可能拦住合法模型名;风险以文档记录,修复
# 需另起一轨(审计格式改分隔或模型名白名单)。
if isinstance(value, str) and value.strip():
return value.strip()
return None
@@ -432,23 +441,38 @@ def load_routing_policy(env=None):
``CLOUD_ROUTING_POLICY_FILE`` is read first, then
``CLOUD_ROUTING_POLICY_JSON`` overrides its fields per tier;
``CLOUD_ROUTING_MODE`` overrides the mode when valid. Any source
that fails to parse is ignored, never fatal. Returns None when no
usable policy was found, so the caller keeps the old behaviour.
that fails to parse is ignored, never fatal, but the failure is
logged as a warning (Audit fix 3, I3): an unconfigured policy
is silent, a configured-but-broken one is not. Returns None
when no usable policy was found, so the caller keeps the old
behaviour.
"""
env = env if env is not None else os.environ
merged = None
# Audit fix 3(I3):区分“未配置策略”(无 env,正常,
# 不记警告)与“配置了但解析失败”(异常,必须可见)。
# 旧版任一来源失败都静默吞掉,运营方无法区分
# “策略生效”与“策略已死”。行为不变:失败仍返回
# None、派发回落旧链,只是失败现在记警告日志;
# worker 侧另有 routing_policy_load_failed 标志与
# 审计(见 worker.py),让失败在运行期也可查。
configured = bool(env.get("CLOUD_ROUTING_POLICY_FILE")
or env.get("CLOUD_ROUTING_POLICY_JSON"))
failures = []
path = env.get("CLOUD_ROUTING_POLICY_FILE") or ""
if path:
try:
with open(path, encoding="utf-8") as f:
merged = json.load(f)
except (OSError, ValueError):
except (OSError, ValueError) as exc:
failures.append("policy file %r: %s" % (path, exc))
merged = None
raw = env.get("CLOUD_ROUTING_POLICY_JSON") or ""
if raw:
try:
override = json.loads(raw)
except ValueError:
except ValueError as exc:
failures.append("CLOUD_ROUTING_POLICY_JSON: %s" % exc)
override = None
if isinstance(override, dict):
if not isinstance(merged, dict):
@@ -463,7 +487,17 @@ def load_routing_policy(env=None):
merged["tiers"] = tiers
policy = parse_routing_policy(merged)
if policy is None:
if configured:
failures.append("merged policy document is unusable")
if failures:
_logger.warning(
"routing policy load failed (%s); falling back to"
" worker default", "; ".join(failures))
return None
if failures:
_logger.warning(
"routing policy partially failed (%s); continuing with"
" the usable source", "; ".join(failures))
mode_override = env.get("CLOUD_ROUTING_MODE") or ""
if mode_override in ROUTING_MODES:
policy.mode = mode_override