fix(run): respect explicit --tool flag when --tier is also specified (#1440)#1444
Conversation
…1440) When a caller passed both `--tier <name>` and `--tool <name>` (e.g. `csa run --tier tier4 --tool claude-code`), the session would still silently fall over to a different tool (gemini-cli) on slot contention. The tool resolution layer correctly pinned the requested tool, but the runtime failover gate ignored that and enabled cross-tool failover whenever a tier was present. Root cause: `allow_cross_tool_failover` granted cross-tool failover under a tier exception clause that triggered even for `ToolSelectionStrategy::Explicit(_)`. Explicit `--tool` is the user's hard selection and must never be silently replaced; tier remains in charge of model selection for the chosen tool via `resolve_requested_tool_from_tier`. Fix: drop the tier exception. `Explicit(_)` strategies block cross-tool failover regardless of tier or force-ignore-tier-setting. The `resolved_tier_name` and `force_ignore_tier_setting` parameters are preserved (renamed to `_resolved_tier_name` / `_force_ignore_tier_setting`) to keep the call sites stable. Regression test: `explicit_tool_in_tier_blocks_cross_tool_failover` asserts the user's bug scenario — `--tier t4` + explicit `ToolName::ClaudeCode` must not enable cross-tool failover. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request updates the workspace version to 0.1.734 and modifies the failover logic in the cli-sub-agent crate. Specifically, it ensures that an explicit tool selection prevents cross-tool failover, even when a tier is specified. The review feedback suggests removing the now-unused parameters from the allow_cross_tool_failover function signature to improve internal API clarity. Additionally, the reviewer noted that the current implementation might be too restrictive by disabling intra-tool model failover when a specific tool is requested alongside a tier, suggesting that the logic should be refined to allow switching between models of the same tool.
| _resolved_tier_name: Option<&str>, | ||
| _force_ignore_tier_setting: bool, |
There was a problem hiding this comment.
The parameters _resolved_tier_name and _force_ignore_tier_setting are now unused in the function body. Since this is a pub(crate) function, it would be cleaner to remove these parameters from the signature and update the call sites, rather than just prefixing them with underscores. This improves the internal API clarity and reduces technical debt.
| // selection: never silently fall over to a different tool, even when a | ||
| // tier is also specified (#1440). Tier still drives model selection for | ||
| // the chosen tool via `resolve_requested_tool_from_tier`. | ||
| !matches!(strategy, ToolSelectionStrategy::Explicit(_)) |
There was a problem hiding this comment.
This change prevents any failover when an explicit tool is selected, even if a --tier is provided. While this correctly addresses the issue of switching to a different tool (cross-tool failover), it also disables intra-tool failover (switching between different models of the same tool within a tier).
If a user specifies both --tool and --tier, they might still expect the system to try other models from that tier that match the selected tool if the first attempt hits a rate limit. By returning false here, the failover logic in the caller is likely bypassed entirely. Consider if the logic should be refined to allow failover but restrict it to the requested tool during the scheduling phase, rather than disabling it completely.
Summary
--toolflag being ignored when--tieris also specifiedtool_is_auto_resolvedwas incorrectly true for user-explicit--tool, causing the tier resolution to skip the tool filter and fall through to auto-selection (which picked gemini-cli via heterogeneous preference)--toolcorrectly filters the tier's model listTest plan
just pre-commitpasses (32/32 tests)csa review --check-verdictPASS (codex gpt-5.5)csa run --tier tier-4-critical --tool claude-codeuses claude-code (not gemini-cli)Closes #1440
🤖 Generated with Claude Code