unsloth/studio/backend/routes
Daniel Han 1b621cd9e7 studio: tighten MTP reload guards and asymmetric spec flags for #5582
Five issues surfaced after #5582 merged. All addressed with matching
pytest coverage (15 new tests, 147 total green).

Bug A -- route guard compared against the requested UI mode rather than
the backend's resolved spec mode. A user request setting
``spec_draft_n_max=2`` against a backend that was auto-promoted from
``auto`` -> ``draft-mtp`` saw ``requested_spec_mode == "auto"`` (not in
``("mtp", "mtp+ngram")``) and skipped the comparison, returning
``already_loaded`` with the stale value still active. Now mirrors the
backend-side guard's check against ``speculative_type == "draft-mtp"``.

Bug B -- both reload guards short-circuited the n_max comparison when
the request value was ``None``, treating it as a wildcard. A backend
loaded with an explicit override of 8 could never be cleared back to
the platform default without swapping the model. Both guards now treat
the ``(None vs explicit)`` flip as a difference: clear-to-default and
set-from-default both bounce a reload, while ``(None == None)`` and
``(N == N)`` continue to match.

Bug C -- chained MTP+ngram on a legacy llama-server (pre arg-rename)
emitted ``--draft-max`` twice: once for MTP's draft length (e.g. 2),
once for ngram-mod's size-N max (e.g. 64). llama-server's last-wins
parsing clobbered the MTP value with 64, defeating the
``--spec-draft-n-max`` slider. ``_build_ngram_mod_flags`` now takes a
``chain_with_mtp`` kwarg that suppresses ``--draft-max`` on the legacy
flavor when MTP will emit it; the post-rename flavor uses distinct
``--spec-ngram-mod-*`` names that cannot collide.

Bug D -- a forced ``speculative_type="ngram"`` request emitted
``--spec-type ngram-mod`` even on binaries that did not advertise
ngram-mod support, causing llama-server to refuse to start. The auto
path already checked ``supports_ngram_mod`` before emitting; the
forced path now mirrors that check and loads without spec (with a
warning that matches the MTP-token-missing path).

Bug E -- ``speculative_type="none"`` is llama.cpp's own explicit-disable
spelling, and external API callers commonly use ``"disable"`` /
``"disabled"``. None of these were in the canonical spec mode set or
the legacy alias map, so they fell through to ``"auto"`` and silently
re-enabled MTP -- the opposite of the user's intent. Added all three
to ``_LEGACY_SPEC_MODE_MAP`` as aliases for ``"off"``.

Tests
-----
- test_canonicalize_spec_mode_none_aliases_map_to_off (6 cases via
  parametrize): "none"/"None"/"NONE"/"  none  "/"disable"/"Disabled"
  all canonicalise to "off".
- test_build_ngram_mod_flags_legacy_chained_omits_draft_max +
  test_build_ngram_mod_flags_legacy_standalone_keeps_draft_max +
  test_build_ngram_mod_flags_new_flavor_always_emits_distinct_names:
  the chain_with_mtp kwarg suppresses only the legacy flavor's
  --draft-max, never the new-flavor knobs.
- test_build_speculative_flags_chained_mtp_ngram_legacy_no_duplicate_draft_max:
  end-to-end check that the assembled spec block has exactly one
  --draft-max carrying the MTP draft length.
- test_build_speculative_flags_forced_ngram_without_support_skips_spec
  + test_build_speculative_flags_forced_ngram_with_support_emits_spec:
  forced ngram refuses on a binary lacking ngram-mod support; still
  emits cleanly on a supporting binary.
- test_already_in_target_state_{clear,set}_explicit_n_max_*_forces_reload:
  backend-side guard covers both clear-to-default and set-from-default.
- test_route_guard_auto_promoted_mtp_{bounces,matches,clear_*}: route
  guard now compares against resolved spec mode and handles the None
  flip symmetrically.
- test_route_guard_ignores_n_max_when_resolved_spec_is_not_mtp:
  non-MTP resolved spec (e.g. ngram-mod) still ignores n_max.

147/147 spec/reload test suites green.
2026-05-23 15:33:15 +00:00
..
data_recipe Studio: fix 7 failing studio_unit_tests on main (#5216) 2026-04-28 22:43:44 -07:00
.gitkeep root studio folder 2026-02-02 09:13:49 +00:00
__init__.py Studio: persist chat history in backend storage (#5272) 2026-05-22 06:18:05 -07:00
auth.py studio: proxy-aware login rate-limit; allow google favicons in CSP (#5489) 2026-05-18 00:02:15 -07:00
chat_history.py Studio: persist chat history in backend storage (#5272) 2026-05-22 06:18:05 -07:00
datasets.py studio: show HF model download progress in training start overlay (#4894) 2026-04-14 08:54:01 -07:00
export.py studio: security and hardening pass (auth rate-limit, sandbox, path containment, schema validation, headers) (#5375) 2026-05-13 06:12:18 -07:00
inference.py studio: tighten MTP reload guards and asymmetric spec flags for #5582 2026-05-23 15:33:15 +00:00
models.py Fix /recommended-folders 500 on unreadable model directories (Python 3.12+) (#5523) 2026-05-18 00:16:14 +04:00
providers.py Studio: per-session cost calculator + /api/providers/pricing endpoint (#5690) 2026-05-22 06:03:43 -07:00
training.py studio: drop unused max_grad_value schema + route plumbing (#5424) 2026-05-14 05:43:58 -07:00
training_history.py Studio: Dark theme refactor, right sidebar redesign, and chat UI polish (#5150) 2026-05-07 14:33:31 +04:00