fix(routing): the task-rule badge only when the rule actually chose the head

route_source reported "+task-rule" whenever a rule existed for the task —
so a math prompt routed low by the ordinary tier chain still wore the badge
next to the local model, reading as "the rule picked this" when it hadn't
(the rule only defines math@high). matched now means the head of the chain
came from the rule's tier-specific or any-tier list; verified live: the same
low math request now reports route_source "router".
This commit is contained in:
infosave2007
2026-08-08 09:02:25 +03:00
parent 06813b3e97
commit b24d4cdbab
+21 -6
View File
@@ -97,9 +97,16 @@ impl RoutingTable {
}
let d = self.default.clone();
push(&mut out, &d);
let matched = rule
.map(|r| !r.any.is_empty() || r.per.values().any(|v| !v.is_empty()))
.unwrap_or(false);
// "task-rule" must mean "the rule chose the head of this chain" — a
// rule that exists but lost to the tier chain (math has a high pick,
// the request came in low) must not claim the credit.
let matched = match (rule, out.first()) {
(Some(r), Some(head)) => {
r.per.get(tier).map(|v| v.contains(head)).unwrap_or(false)
|| r.any.first() == Some(head)
}
_ => false,
};
(out, matched)
}
@@ -184,7 +191,9 @@ mod tests {
assert_eq!(c[0], "cheap-coder");
// high: tier chain leads, task rule follows as fallback
let (c, m) = t.candidates_for("code", "high");
assert!(m);
// escalation put the global high chain first → the rule did not pick
// the head, so no task-rule credit
assert!(!m);
// default rides along as the very last fallback
assert_eq!(c, vec!["big", "cheap-coder", "cheap"]);
}
@@ -202,8 +211,10 @@ mod tests {
let (c, m) = t.candidates_for("code", "high");
assert!(m);
assert_eq!(c, vec!["best-coder", "big", "generic-coder", "cheap"]);
// at low: any-tier task models lead as before
let (c, _) = t.candidates_for("code", "low");
// at low: any-tier task models lead as before (and the badge is
// honest — the head came from the rule)
let (c, m) = t.candidates_for("code", "low");
assert!(m);
assert_eq!(c, vec!["generic-coder", "cheap"]);
// a tier with an explicit pick but no any-models
let t2 = with_task_tier_models(
@@ -215,6 +226,10 @@ mod tests {
let (c, m) = t2.candidates_for("legal", "high");
assert!(m);
assert_eq!(c, vec!["strong", "big", "cheap"]);
// the same rule at LOW did not shape the head → no task-rule credit
let (c, m) = t2.candidates_for("legal", "low");
assert!(!m);
assert_eq!(c, vec!["cheap"]);
}
#[test]