diff --git a/mcp-server/search.html b/mcp-server/search.html
index bb6e1fb..5a58d16 100644
--- a/mcp-server/search.html
+++ b/mcp-server/search.html
@@ -74,23 +74,54 @@ function api(path,body){
}
function loadDay(){
- Promise.all([
- api('/simulation/run',{}),
- api('/sql',{sql:"SELECT role, COUNT(*) total, SUM(CASE WHEN CAST(reliability AS DOUBLE)>0.8 THEN 1 ELSE 0 END) reliable FROM workers_500k GROUP BY role ORDER BY total DESC LIMIT 5"}),
- api('/sql',{sql:"SELECT name, role, city, state, ROUND(CAST(reliability AS DOUBLE),2) rel, certifications FROM workers_500k WHERE CAST(reliability AS DOUBLE)>0.95 ORDER BY CAST(reliability AS DOUBLE) DESC LIMIT 5"}),
- api('/sql',{sql:"SELECT state, COUNT(*) cnt, SUM(CASE WHEN CAST(reliability AS DOUBLE)>0.8 THEN 1 ELSE 0 END) good FROM workers_500k GROUP BY state ORDER BY cnt DESC LIMIT 5"})
- ]).then(function(results){
- var sim=results[0], roles=results[1], topWorkers=results[2], coverage=results[3];
+ // Step 1: run simulation first
+ api('/simulation/run',{}).then(function(sim){
var today=sim.days?sim.days[0]:null;
var sum=sim.summary||{};
document.getElementById('status').textContent=sum.total_filled+'/'+sum.total_needed+' positions filled across '+sum.total_contracts+' contracts';
- renderMain(today,sum,roles,topWorkers,coverage);
+
+ // Step 2: extract what's ACTUALLY needed from today's contracts
+ var contracts=today?today.contracts:[];
+ var needRoles={}, needStates={}, urgentRoles=[];
+ contracts.forEach(function(c){
+ if(c.filled0.85 ORDER BY CAST(reliability AS DOUBLE) DESC LIMIT 8";
+
+ // Coverage for states that matter today
+ var covSql="SELECT state, COUNT(*) cnt, SUM(CASE WHEN CAST(reliability AS DOUBLE)>0.8 THEN 1 ELSE 0 END) good "+
+ "FROM workers_500k WHERE state IN ("+stateFilter+") GROUP BY state ORDER BY cnt DESC";
+
+ // Roles breakdown for today's needed roles
+ var roleSql="SELECT role, COUNT(*) total, SUM(CASE WHEN CAST(reliability AS DOUBLE)>0.8 THEN 1 ELSE 0 END) reliable "+
+ "FROM workers_500k WHERE role IN ("+roleFilter+") GROUP BY role ORDER BY total DESC";
+
+ return Promise.all([roleSql, topSql, covSql].map(function(sql){
+ return api('/sql',{sql:sql});
+ })).then(function(results){
+ var roles=results[0], topWorkers=results[1], coverage=results[2];
+ renderMain(today,sum,roles,topWorkers,coverage,needRoles,needStates);
+ });
}).catch(function(e){
document.getElementById('main').textContent='Error loading: '+e.message;
});
}
-function renderMain(today,sum,roles,topWorkers,coverage){
+function renderMain(today,sum,roles,topWorkers,coverage,needRoles,needStates){
var el=document.getElementById('main');
el.textContent='';
@@ -159,37 +190,48 @@ function renderMain(today,sum,roles,topWorkers,coverage){
}
}
- // INSIGHT 2: Top available workers they should know about
+ // INSIGHT 2: Top available workers — contextual to today's unfilled contracts
if(topWorkers&&topWorkers.rows&&topWorkers.rows.length){
- var ins3=makeInsight('info','Your Strongest Available Workers',
- 'These workers have 95%+ reliability — they rarely no-show and clients request them back',
- 'Based on placement history and performance tracking. Consider these first for high-priority contracts.');
+ // Build a contextual headline from today's gaps
+ var gapRoles=needRoles?Object.keys(needRoles):[];
+ var gapStates=needStates?Object.keys(needStates):[];
+ var headline='Workers Available for Today\'s Open Contracts';
+ var sub='Matched to the roles and locations you need filled right now';
+ if(gapRoles.length<=3&&gapRoles.length>0){
+ headline='Top '+gapRoles.join(', ')+' Workers Available';
+ sub='These workers match your unfilled contracts in '+gapStates.join(', ');
+ }
+ var ins3=makeInsight('info',headline,sub,
+ 'Filtered to roles and states with open positions today. Reliability 85%+.');
topWorkers.rows.forEach(function(w,i){
+ // Show which contract gap this worker could fill
+ var gapNote='';
+ if(needRoles&&needRoles[w.role]){gapNote='→ Could fill '+needRoles[w.role]+' open '+w.role+' spot'+(needRoles[w.role]>1?'s':'')}
var wd={nm:w.name,role:w.role,loc:w.city+', '+w.state,skills:[],
certs:(w.certifications||'').split(',').filter(function(c){return c.trim()&&c.trim()!=='none'}),
rel:w.rel,avail:0,arch:'',hasM:true};
addWorkerInsight(ins3,w.name,w.role+' · '+w.city+', '+w.state,
- 'Reliability: '+w.rel*100+'% · Certs: '+(w.certifications||'none'),i,null,wd);
+ 'Reliability: '+Math.round(w.rel*100)+'%'+(w.certifications&&w.certifications!=='none'?' · Certs: '+w.certifications:'')+(gapNote?' · '+gapNote:''),i,null,wd);
});
el.appendChild(ins3);
}
- // INSIGHT 3: Coverage warning
- if(coverage&&coverage.rows){
- var thin=coverage.rows.filter(function(r){return r.good/r.cnt<0.45});
- if(thin.length){
- var ins4=makeInsight('warning','Bench Strength Alert',
- 'Some states have fewer reliable workers than usual',
- 'The system monitors your worker pool and flags when coverage drops. Consider recruiting in these areas.');
- thin.forEach(function(r){
- var pct=Math.round(r.good/r.cnt*100);
- var d=document.createElement('div');d.style.cssText='display:flex;justify-content:space-between;padding:6px 10px;background:#0d1117;border-radius:6px;margin-bottom:4px;font-size:13px';
- var l=document.createElement('span');l.textContent=r.state+' — '+r.cnt.toLocaleString()+' workers';l.style.color='#f0f6fc';
- var v=document.createElement('span');v.textContent=pct+'% reliable';v.style.color=pct<40?'#f85149':'#d29922';
- d.appendChild(l);d.appendChild(v);ins4.appendChild(d);
- });
- el.appendChild(ins4);
- }
+ // INSIGHT 3: Coverage for states with active contracts today
+ if(coverage&&coverage.rows&&coverage.rows.length){
+ var stateLabel=gapStates.length?' in '+gapStates.join(', '):'';
+ var ins4=makeInsight('warning','Bench Strength'+stateLabel,
+ 'Worker pool depth for states with open contracts today',
+ 'Shows how many reliable workers (80%+ reliability) you have in states where you need to fill positions right now.');
+ coverage.rows.forEach(function(r){
+ var pct=Math.round(r.good/r.cnt*100);
+ var openSlots=needStates&&needStates[r.state]?needStates[r.state]:0;
+ var d=document.createElement('div');d.style.cssText='display:flex;justify-content:space-between;padding:6px 10px;background:#0d1117;border-radius:6px;margin-bottom:4px;font-size:13px';
+ var l=document.createElement('span');l.style.color='#f0f6fc';
+ l.textContent=r.state+' — '+r.cnt.toLocaleString()+' workers'+(openSlots?' · '+openSlots+' open slot'+(openSlots>1?'s':''):'');
+ var v=document.createElement('span');v.textContent=pct+'% reliable';v.style.color=pct<40?'#f85149':'#d29922';
+ d.appendChild(l);d.appendChild(v);ins4.appendChild(d);
+ });
+ el.appendChild(ins4);
}
}