Skip to content

fix(tui): Ctrl+T moves to a new effective thinking tier on fixed routes - #6667

Merged
2 commits merged into
mainfrom
fix/6650-ctrl-t-effort-cycle
Sep 28, 2026
Merged

2 commits merged into
mainfrom
fix/6650-ctrl-t-effort-cycle

Conversation

@Hmbown

@Hmbown Hmbown commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Refs #6650

The reporter's case (fixed deepseek-v4.1-flash, dead presses) was not reproduced, so this PR does not close the issue. See Uncertain.

Cause

  • Auto routing: Ctrl+T used cycle_next_for_auto_model, a separate 9-rung ladder (minimal, xhigh, ultra, …) that did not match the /model picker's Auto ladder.
  • Fixed routes: picker_efforts_for_route removed only exact duplicate values. It kept rungs that resolve to the same tier on the route: DeepSeek medium is high, Z.ai GLM-5.2 low/medium are high, K3 off is low, and a catalog thinking: disabled value becomes the catalog default. DeepSeek route normalization also left minimal/xhigh/ultra unchanged, but the wire sends them as low/high/max.

Fix

  • Ctrl+T and the hotbar reasoning.cycle action now cycle exactly picker_efforts_for_route(…, auto_model).
  • On a fixed route, that ladder drops any rung whose effective tier is already offered. The effective tier comes from model_picker::effective_tier_for_route, which returns the route-constrained tier when the route proves one (the value the status line and Work receipts report) and otherwise normalize_for_route. When two rungs collide, the one that names the tier stays. Auto is always kept. Routes whose tier is unavailable or untiered keep all their rows.
  • A saved value that the ladder dropped (for example DeepSeek medium) starts from the rung it resolves to, so the first press moves on.
  • DeepSeek normalize_for_route now matches client::deepseek_effort, so /status, receipts and /effort xhigh report high, not xhigh. K3's picker no longer lists off. cycle_next_for_auto_model is deleted.

Not covered

  • Auto model routing walks the picker's Auto ladder [auto, off, low, medium, high, max]. Its tier is settled when the turn is routed. If the turn goes to DeepSeek, medium and high both send high. The CHANGELOG says so.
  • Codex minimal and low both send low. This PR does not dedupe them.

Evidence

cargo test -p codewhale-tui --lib -- <filter> (CARGO_BUILD_JOBS=4) on head:

  • ctrl_t: 6 passed; 0 failed.
    • every_ctrl_t_press_changes_the_effective_thinking_tier checks that the effective tier changes on every press, not the label. It covers DeepSeek flash and v4.1, K3 and Grok, over two laps.
    • ctrl_t_skips_catalog_rungs_that_resolve_to_an_offered_tier injects catalog rows: DeepSeek low/medium/high/xhigh/max and GLM-5.2 off/low/medium/high/max. It asserts the ladders [auto, low, high, max] and [auto, off, high, max] and checks that every press changes the effective tier.
    • With the dedupe disabled, this test fails with "deepseek-v4.1-flash: press 2 (High) left the effective tier at Tier(High)". With a dedupe that uses only normalize_for_route, it fails with "GLM-5.2: press 2 (Medium) left the effective tier at Tier(High)".
  • Other filters: picker 341/0, reasoning 233/0, effort 80/0, zai 31/0, hotbar 82/0, kimi 118/0, deepseek 167/0. cargo fmt --all -- --check is clean.
  • First commit only (not rerun on head): cycle 152/0, route 762/0, receipt 308/0, status 249/0, tui::ui::tests 824/0.

Uncertain

With the pinned catalog snapshot, the fixed deepseek-v4.1-flash ladder was already distinct on v0.10.0: [auto, off, low, high, max]. On the old Auto path, each press showed a different requested label. The reporter's visible dead presses may come from a live Models.dev entry for the model that lists medium/xhigh, and this PR covers that case. The exact live catalog and config were not reproduced, so the issue stays open until the reporter confirms.

🤖 Generated with Claude Code

Cause: Ctrl+T could land on a tier the route already treats as the one in
effect, so presses looked dead.
- Under Auto routing, next_reasoning_effort_for_active_route used
  cycle_next_for_auto_model, a private 9-rung ladder (minimal, xhigh,
  ultra...) that disagreed with the /model picker's Auto ladder.
- picker_efforts_for_route deduped only identical values, not rungs whose
  route-normalized tier is identical (DeepSeek medium -> high, K3 off ->
  low, catalog `thinking: disabled` -> catalog default), and DeepSeek route
  normalization kept minimal/xhigh/ultra although the wire sends them as
  low/high/max.

Fix: Ctrl+T and the hotbar reasoning.cycle action cycle exactly
picker_efforts_for_route (Auto included). That ladder now drops rungs whose
route-normalized tier is already offered, preferring the rung that names the
tier (Auto is always kept). A persisted alias the ladder dropped enters at
the rung it resolves to, so the first press moves on. DeepSeek
normalize_for_route now mirrors client::deepseek_effort (minimal -> low,
xhigh -> high, ultra -> max). K3's picker no longer lists `off`.
cycle_next_for_auto_model is deleted.

Tests (cargo test -p codewhale-tui --lib -- <filter>):
- ctrl_t: 5 passed; 0 failed (3 of them fail with the fix stashed)
- picker: 341 passed; 0 failed
- reasoning: 233 passed; 0 failed
- cycle: 152 passed; 0 failed; deepseek: 167 passed; 0 failed
- kimi: 118 passed; 0 failed; route: 762 passed; 0 failed
- receipt: 308 passed; 0 failed; status: 249 passed; 0 failed
- hotbar: 82 passed; 0 failed; tui::ui::tests: 824 passed; 0 failed
cargo fmt --all -- --check clean.

Refs #6650

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 27, 2026 03:32
@Hmbown Hmbown added this to the v0.10.1 milestone Sep 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-27T03:35:22.216646Z 7f8884c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Cause: the #6650 ladder dedupe used only normalize_for_route, while the
effort status line and Work receipts also apply the route-constrained tier
(work_graph::constrained_effective_reasoning_for_route). On Z.ai GLM-5.2
low and medium both resolve to high, so a catalog listing low/medium/high
still produced presses that changed nothing. The regression test compared
display labels, which under Auto routing are the requested value, so it
never proved the effective tier changed and never ran the dedupe path
through cycle_effort.

Fix: add model_picker::effective_tier_for_route (constrained tier when the
route proves one, else normalize_for_route) and use it for both the ladder
dedupe and the Ctrl+T anchor for a persisted alias. Routes whose tier is
unavailable or untiered keep their rows. Auto model routing is unchanged:
it walks the picker's Auto ladder and its tier is settled at dispatch, so
the CHANGELOG no longer claims every press changes the tier there. The
CHANGELOG now also notes the DeepSeek minimal/xhigh/ultra reporting change
and K3 dropping `off`; the stale DeepSeek note in reasoning_preference.rs is
corrected.

Tests: the Ctrl+T test now compares the effective tier after each press on
concrete routes, and a new test injects catalog rows (DeepSeek
low/medium/high/xhigh/max, Z.ai GLM-5.2 off/low/medium/high/max) and walks
them through cycle_effort. With the dedupe disabled it fails (deepseek press
2 left the tier at High); with only normalize_for_route it fails (GLM-5.2
press 2 left the tier at High).

cargo test -p codewhale-tui --lib -- <filter>, CARGO_BUILD_JOBS=4:
- ctrl_t: 6 passed; 0 failed
- picker: 341 passed; 0 failed
- reasoning: 233 passed; 0 failed
- effort: 80 passed; 0 failed
- zai: 31 passed; 0 failed
- hotbar: 82 passed; 0 failed
- kimi: 118 passed; 0 failed
- deepseek: 167 passed; 0 failed
cargo fmt --all -- --check clean.

Refs #6650

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Hmbown Hmbown changed the title fix(tui): every Ctrl+T press changes the effective thinking tier (#6650) fix(tui): Ctrl+T moves to a new effective thinking tier on fixed routes Sep 27, 2026
@Hmbown
Hmbown force-pushed the fix/6650-ctrl-t-effort-cycle branch from fd383c8 to 9226111 Compare September 27, 2026 10:20
Hmbown pushed a commit that referenced this pull request Sep 27, 2026
# Conflicts:
#	CHANGELOG.md
#	crates/tui/CHANGELOG.md
@Hmbown Hmbown closed this pull request by merging all changes into main in 0bfe04e Sep 28, 2026
@Hmbown
Hmbown deleted the fix/6650-ctrl-t-effort-cycle branch September 28, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants