Skip to content

[staging CI] unslothai/unsloth#8267 - #244

Open
danielhanchen wants to merge 19 commits into
mainfrom
pr-8267-ci
Open

[staging CI] unslothai/unsloth#8267#244
danielhanchen wants to merge 19 commits into
mainfrom
pr-8267-ci

Conversation

@danielhanchen

Copy link
Copy Markdown
Collaborator

Disposable CI run for unslothai/unsloth#8267. Do not merge; closed after CI.

oobabooga and others added 19 commits August 9, 2026 12:28
…he UI

A dit_block clears the family-level chip fields (params, qlora_vram_gb, gated,
note) precisely so FamilyFacts falls through to vram_note, which carries the
actionable reason: no CUDA, or no native bf16 on this GPU. base_specs was still
published though, and the per-base entry wins in resolveDiffusionTrainingFacts,
so selecting Klein base-9B on a blocked host put the 9B and 18 GB chips straight
back. FamilyFacts renders vram_note only when there are no chips, so the user
lost the explanation and got a generic refusal plus a size they cannot act on.

Clear base_specs on the same condition. The overlay only ever feeds those chips
(resolveDiffusionTrainingFacts is its sole consumer), so nothing functional
depends on it being present.

Covered by a test that pins a bf16-unsupported host and asserts both halves: the
overlay is empty and vram_note still carries the reason. It also asserts a
per-base overlay exists on an unblocked host first, so it cannot pass vacuously.
Verified it fails with the fix reverted.
Two consequences of routing the fetch through prefer_ungated_mirror that
the mirror was not meant to have.

The gated-repo name check ran on the canonical id while the start route
preflighted the fetch repo. For FLUX.1-dev or FLUX.2-dev without a token
that means the route probes the public mirror, answers 200, frees the
resident models, and only then does the child refuse the run by name. It
now checks the repo the run will actually fetch, so the two agree: a
mirror-backed run proceeds, and a genuinely gated fetch still fails in
the route, before anything is evicted.

base_revision was reading the fetch repo too. Which repo that is depends
on local cache state, so the same base records a different rev- value
once the upstream snapshot is evicted or the run moves to another
machine, and mismatch_reason then refuses the checkpoint as a different
base revision though the weights are byte identical. Every checkpoint
written before mirrors existed holds the canonical value, so those would
be refused as well. Both identity_for_config and the post-load re-read go
back to the canonical id; a canonical repo with no local ref records
"unresolved", which is already treated as not comparable.

Tests, both mutation checked: the gate assertion fails when the canonical
id is restored, and the revision assertion fails when the fetch repo is.
A mirror-backed run resolves the revision from the mirror, so recording the canonical
repo's revision instead lost validation entirely: source_revision(canonical) is
"unresolved" on exactly the hosts a mirror is selected for, and mismatch_reason skips
non-comparable revisions, so the check silently never fired. Record both halves and
compare them only when the repos match, which still catches a moved mirror and no
longer refuses a legitimate cross-repo resume. Bundles written before the field exist
keep comparing as they did.

Also take the mirror on a token-less run even when the vendor repo is cached: only
gated repos are in the mirror table, so a mirror existing means the upstream needs
credentials this run does not have. UNSLOTH_DIFFUSION_NO_MIRROR still pins the vendor
repo.

And preselect the training base a family pairs with a loaded distilled checkpoint: the
distilled half is never in base_repos, so opening Train with the 9B model loaded seeded
the 4B base.
The mirror table stopped being gated-only when the redistributable bases joined it, so
"a mirror exists" no longer implies "the upstream needs credentials". Klein base-4B is
both a default trainable base and mirrored, and the Hub serves it anonymously, so a
token-less run with a complete local cache was re-pulling it from the mirror and an
offline run failed outright.

Split the table rather than keep a second list in sync: the 12 genuinely gated pairs
stay in _GATED_MIRROR_PAIRS, the redistributable ones move to _UNGATED_MIRROR_PAIRS,
and mirror_repo and canonical_base build from the union so redirection and the
base-keyed table normalisation are unchanged. upstream_is_gated reads the gated half,
and the token-less override now asks it.
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