Audit batch 4: I-6 whitespace audit format, I-7 explicit non-sub2api capability gate, I-8 coord gate attribution, I-10 checked gates, I-11 gate-without-finding escalate, I-13 structured-first classification
This commit is contained in:
1 parent
06e4e16bbb
commit
cdac8039b3
5 files changed
+959
-47
No files matched your search
+54
-11
@@ -155,7 +155,11 @@ def parse_model_capabilities(raw):
|
||||
return out
|
||||
for model, entry in raw.items():
|
||||
model = _clean_model_name(model)
|
||||
if not model or not isinstance(entry, dict):
|
||||
# 审计批 4(I-6):能力目录键含空白时整条丢弃——
|
||||
# 含空白的键在空白分隔的审计 detail 里无法被消费点
|
||||
# 稳健识别,保留它只会让能力检查静默走 unknown。
|
||||
if not model or _model_name_has_whitespace(model) \
|
||||
or not isinstance(entry, dict):
|
||||
continue
|
||||
cleaned = {}
|
||||
valid = True
|
||||
@@ -432,17 +436,28 @@ def classify_task(task) -> str:
|
||||
|
||||
|
||||
def _clean_model_name(value):
|
||||
# Audit fix 3(M7,文档级):只 strip、不校验字符集。
|
||||
# 含空白的模型名仍会原样进审计 detail,而影子审计
|
||||
# 格式是空白分隔,整行解析失败即无声丢样本(不报错、
|
||||
# 不计数)。这里不加字符集校验——那会改变模型名接受
|
||||
# 语义、可能拦住合法模型名;风险以文档记录,修复
|
||||
# 需另起一轨(审计格式改分隔或模型名白名单)。
|
||||
"""把模型名规范成可比较的字符串:仅 strip。
|
||||
|
||||
注意:这里刻意不做空白白名单。decide_routing 里清洗后
|
||||
的 None 会被当成“无显式模型”而改走策略/worker 默认路由,
|
||||
全局白名单会把“显式模型含空白(目前原样派发、provider
|
||||
侧 loud fail)”悄悄改成“静默替换用户选型”,比现状更差。
|
||||
空白模型名的处理因此分两层(审计批 4,I-6):
|
||||
(a) 策略写入路径白名单——能力目录键、档模型、
|
||||
fallback_models 含空白的一律丢弃;(b) 运行时消费点
|
||||
稳健解析——影子 chosen 贪到行尾、_is_persisted_model
|
||||
按键提取 model 值,不再依赖空白分隔的位置。
|
||||
"""
|
||||
if isinstance(value, str) and value.strip():
|
||||
return value.strip()
|
||||
return None
|
||||
|
||||
|
||||
def _model_name_has_whitespace(name):
|
||||
"""清洗后的模型名是否含空白(审计批 4,I-6 白名单判定)。"""
|
||||
return isinstance(name, str) and any(ch.isspace() for ch in name)
|
||||
|
||||
|
||||
def _clean_tiers(raw):
|
||||
"""Return {tier: model} keeping only valid non-empty entries."""
|
||||
tiers = {}
|
||||
@@ -450,13 +465,17 @@ def _clean_tiers(raw):
|
||||
return tiers
|
||||
for tier in ROUTING_TIERS:
|
||||
model = _clean_model_name(raw.get(tier))
|
||||
if isinstance(model, str):
|
||||
# 审计批 4(I-6):档模型含空白时整档丢弃(parse 层
|
||||
# 另行记入 dropped_tiers + 警告),不让含空白的模型
|
||||
# 名进空白分隔的审计 detail。
|
||||
if isinstance(model, str) \
|
||||
and not _model_name_has_whitespace(model):
|
||||
# A tier entry may itself be a dict {"model": ...}; accept
|
||||
# that shape too so policy authors are not punished for it.
|
||||
tiers[tier] = model
|
||||
elif isinstance(raw.get(tier), dict):
|
||||
model = _clean_model_name(raw[tier].get("model"))
|
||||
if model:
|
||||
if model and not _model_name_has_whitespace(model):
|
||||
tiers[tier] = model
|
||||
return tiers
|
||||
|
||||
@@ -501,7 +520,12 @@ class RoutingPolicy:
|
||||
self.version = version if isinstance(version, str) \
|
||||
and version.strip() else None
|
||||
self.mode = mode if mode in ROUTING_MODES else "off"
|
||||
self.tiers = dict(tiers or {})
|
||||
# 审计批 4(I-6):直接构造的策略同样过白名单——含
|
||||
# 空白的档模型进不了空白分隔的审计 detail,整档丢弃
|
||||
# (与 parse 层口径一致;parse 层另行记 dropped_tiers)。
|
||||
self.tiers = {tier: model for tier, model in (tiers or {}).items()
|
||||
if not (isinstance(model, str)
|
||||
and _model_name_has_whitespace(model))}
|
||||
self.tier_modes = {}
|
||||
for tier, tier_mode in (tier_modes or {}).items():
|
||||
if tier in self.tiers and tier_mode in ROUTING_MODES:
|
||||
@@ -517,7 +541,9 @@ class RoutingPolicy:
|
||||
self.fallback_models = []
|
||||
for item in fallback_models or []:
|
||||
model = _clean_model_name(item)
|
||||
if model and model not in self.fallback_models:
|
||||
# 审计批 4(I-6):fallback 模型名同款白名单。
|
||||
if model and not _model_name_has_whitespace(model) \
|
||||
and model not in self.fallback_models:
|
||||
self.fallback_models.append(model)
|
||||
self.model_capabilities = parse_model_capabilities(
|
||||
model_capabilities)
|
||||
@@ -598,6 +624,23 @@ def parse_routing_policy(data):
|
||||
# for an empty model) is not a second drop and is not logged:
|
||||
# the warning must name a tier this pop really removed.
|
||||
dropped_tiers = []
|
||||
# 审计批 4(I-6):_clean_tiers 已把含空白模型名的档
|
||||
# 丢掉,这里只记名——与无效模式/无效 requires 的 pop
|
||||
# 同款可见性。只认 ROUTING_TIERS 内的档(未知档名本
|
||||
# 来就被 _clean_tiers 忽略,不是“被丢弃”);档已被
|
||||
# _clean_tiers 滤掉时,后面的 mode/requires pop 因
|
||||
# `tier in tiers` 为假不会重复记,不会双计。
|
||||
for tier, entry in raw_tiers.items():
|
||||
if tier not in ROUTING_TIERS or tier in tiers:
|
||||
continue
|
||||
raw_model = entry if isinstance(entry, str) else \
|
||||
entry.get("model") if isinstance(entry, dict) else None
|
||||
cleaned = _clean_model_name(raw_model)
|
||||
if cleaned and _model_name_has_whitespace(cleaned):
|
||||
dropped_tiers.append(tier)
|
||||
_logger.warning(
|
||||
"routing policy tier %r dropped: model name contains"
|
||||
" whitespace %r", tier, cleaned)
|
||||
tier_modes = {}
|
||||
for tier, entry in raw_tiers.items():
|
||||
if not isinstance(entry, dict) or "mode" not in entry:
|
||||
|
||||
Reference in new issue
Block a user