diff --git a/static/js/cookbook-hwfit.js b/static/js/cookbook-hwfit.js
index d8652d02e..753009dc5 100644
--- a/static/js/cookbook-hwfit.js
+++ b/static/js/cookbook-hwfit.js
@@ -159,8 +159,17 @@ export function _renderGpuToggles(system) {
// visual highlight. Before this, _activeCount stayed undefined → no
// gpu_count param sent → backend's fallback could rank against RAM on
// mixed-resource boxes ("tightest" sorted by RAM instead of GPU).
- if (container._activeCount === undefined && validCounts.length) {
- container._activeCount = maxGpu;
+ //
+ // On boxes where total RAM > total VRAM, default to RAM (count=0) instead
+ // — RAM is the dominant pool so it's the better starting filter.
+ if (container._activeCount === undefined) {
+ const ramGb = Number(system.total_ram_gb) || 0;
+ const vramGb = Number(system.gpu_vram_gb) || 0;
+ if (ramGb > vramGb) {
+ container._activeCount = 0;
+ } else if (validCounts.length) {
+ container._activeCount = maxGpu;
+ }
}
html += '';
const hasExplicitCount = typeof container._activeCount === 'number';
@@ -363,7 +372,7 @@ function _scanSig() {
hk: _currentServerValue(),
u: document.getElementById('hwfit-usecase')?.value || '',
s: document.getElementById('hwfit-search')?.value?.trim() || '',
- o: sortEl?.value || 'score',
+ o: sortEl?.value || 'newest',
r: sortEl?.dataset.reverse === '1' ? 1 : 0,
q: document.getElementById('hwfit-quant')?.value || '',
c: _ctxValue(),
@@ -582,7 +591,7 @@ export async function _hwfitFetch(fresh = false) {
}).catch(() => {});
}
try {
- const sortBy = document.getElementById('hwfit-sort')?.value || 'score';
+ const sortBy = document.getElementById('hwfit-sort')?.value || 'newest';
const quantPref = document.getElementById('hwfit-quant')?.value || '';
const targetCtx = _ctxValue();
// Get active GPU count from toggles
@@ -710,7 +719,7 @@ export async function _hwfitFetch(fresh = false) {
// 1st click on a column = highest first; clicking it again = lowest first.
if (!isImageMode) {
const sortSel = document.getElementById('hwfit-sort');
- const sortKey = sortSel?.value || 'score';
+ const sortKey = sortSel?.value || 'newest';
const asc = sortSel?.dataset.reverse === '1'; // reversed → ascending (lowest first)
if (sortKey === 'fit') {
// fit_level is categorical (perfect→good→marginal→too_tight), not numeric,
@@ -723,6 +732,18 @@ export async function _hwfitFetch(fresh = false) {
const as = Number(a.score) || 0, bs = Number(b.score) || 0;
return asc ? as - bs : bs - as;
});
+ } else if (sortKey === 'newest') {
+ // release_date is an ISO-ish "YYYY-MM-DD" string — lexical sort is
+ // chronological. Default direction: newest first (reverse=undefined).
+ data.models.sort((a, b) => {
+ const ad = String(a.release_date || ''), bd = String(b.release_date || '');
+ if (ad === bd) return 0;
+ // Empty dates land last regardless of direction so the column never
+ // floats undated rows above real releases.
+ if (!ad) return 1;
+ if (!bd) return -1;
+ return asc ? (ad < bd ? -1 : 1) : (ad < bd ? 1 : -1);
+ });
} else {
const field = { score: 'score', vram: 'required_gb', speed: 'speed_tps', params: 'params_b', context: 'context' }[sortKey] || 'score';
data.models.sort((a, b) => {
@@ -968,7 +989,7 @@ function _modeLabel(model) {
export const _hwfitColumns = [
{ key: 'fit', label: 'Fit', cls: 'hwfit-fit' },
- { key: null, label: 'Model', cls: 'hwfit-name' },
+ { key: 'newest', label: 'Model (latest)', cls: 'hwfit-name' },
{ key: 'params',label: 'Param', cls: 'hwfit-c-params' },
{ key: null, label: 'Quant', cls: 'hwfit-c-quant' },
{ key: 'vram', label: 'VRAM', cls: 'hwfit-c-vram' },
@@ -998,7 +1019,7 @@ export function _hwfitRenderList(el, models) {
return;
}
const sortSel = document.getElementById('hwfit-sort');
- const currentSort = sortSel?.value || 'score';
+ const currentSort = sortSel?.value || 'newest';
const isReversed = sortSel?.dataset.reverse === '1';
// Active budget for the Fit column label \u2014 make it obvious whether the
// ranking is against GPU or RAM so "tightest" can't be ambiguous on a
@@ -1027,6 +1048,13 @@ export function _hwfitRenderList(el, models) {
// (Budget tag removed — the GPU/RAM/N-GPU suffix next to "Fit" was noise;
// the toggle row already shows which budget is active.)
}
+ // The Model column's "(newest)" / "(oldest)" suffix flips with the sort
+ // direction so the user can see at a glance which way they're sorted.
+ if (col.key === 'newest' && col.key === currentSort) {
+ label = isReversed ? 'Model (oldest)' : 'Model (latest)';
+ } else if (col.key === 'newest') {
+ label = 'Model (latest)';
+ }
html += `${label}${arrow}`;
}
html += '';