Contextual insights: workers and bench strength driven by today's actual contracts

- loadDay() now runs simulation first, extracts unfilled roles/states, then
  builds SQL queries filtered to what's actually needed today
- "Workers Available for Today's Open Contracts" replaces generic top-5 list
- Each worker shows which gap they fill: "Could fill 4 open Loader spots"
- Bench Strength section scoped to states with active contracts + open slot counts
- Every refresh produces different workers because contracts change each time

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
root 2026-04-17 17:04:39 -05:00
parent be7436b6f0
commit e9b5498f43

View File

@ -74,23 +74,54 @@ function api(path,body){
} }
function loadDay(){ function loadDay(){
Promise.all([ // Step 1: run simulation first
api('/simulation/run',{}), api('/simulation/run',{}).then(function(sim){
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];
var today=sim.days?sim.days[0]:null; var today=sim.days?sim.days[0]:null;
var sum=sim.summary||{}; var sum=sim.summary||{};
document.getElementById('status').textContent=sum.total_filled+'/'+sum.total_needed+' positions filled across '+sum.total_contracts+' contracts'; 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.filled<c.headcount){
needRoles[c.role]=(needRoles[c.role]||0)+(c.headcount-c.filled);
needStates[c.state]=(needStates[c.state]||0)+(c.headcount-c.filled);
if(c.priority==='urgent'||c.priority==='high') urgentRoles.push(c.role);
}
});
// Build contextual queries based on today's gaps
var roleList=Object.keys(needRoles);
var stateList=Object.keys(needStates);
var roleFilter=roleList.length?roleList.map(function(r){return"'"+r.replace(/'/g,"''")+"'"}).join(','):"'Forklift Operator'";
var stateFilter=stateList.length?stateList.map(function(s){return"'"+s.replace(/'/g,"''")+"'"}).join(','):"'IL'";
// Contextual: workers who match TODAY's unfilled roles+states, randomized within tier
var topSql="SELECT name, role, city, state, ROUND(CAST(reliability AS DOUBLE),2) rel, certifications "+
"FROM workers_500k WHERE role IN ("+roleFilter+") AND state IN ("+stateFilter+") "+
"AND CAST(reliability AS DOUBLE)>0.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){ }).catch(function(e){
document.getElementById('main').textContent='Error loading: '+e.message; 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'); var el=document.getElementById('main');
el.textContent=''; 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){ if(topWorkers&&topWorkers.rows&&topWorkers.rows.length){
var ins3=makeInsight('info','Your Strongest Available Workers', // Build a contextual headline from today's gaps
'These workers have 95%+ reliability — they rarely no-show and clients request them back', var gapRoles=needRoles?Object.keys(needRoles):[];
'Based on placement history and performance tracking. Consider these first for high-priority contracts.'); 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){ 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:[], 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'}), certs:(w.certifications||'').split(',').filter(function(c){return c.trim()&&c.trim()!=='none'}),
rel:w.rel,avail:0,arch:'',hasM:true}; rel:w.rel,avail:0,arch:'',hasM:true};
addWorkerInsight(ins3,w.name,w.role+' · '+w.city+', '+w.state, 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); el.appendChild(ins3);
} }
// INSIGHT 3: Coverage warning // INSIGHT 3: Coverage for states with active contracts today
if(coverage&&coverage.rows){ if(coverage&&coverage.rows&&coverage.rows.length){
var thin=coverage.rows.filter(function(r){return r.good/r.cnt<0.45}); var stateLabel=gapStates.length?' in '+gapStates.join(', '):'';
if(thin.length){ var ins4=makeInsight('warning','Bench Strength'+stateLabel,
var ins4=makeInsight('warning','Bench Strength Alert', 'Worker pool depth for states with open contracts today',
'Some states have fewer reliable workers than usual', 'Shows how many reliable workers (80%+ reliability) you have in states where you need to fill positions right now.');
'The system monitors your worker pool and flags when coverage drops. Consider recruiting in these areas.'); coverage.rows.forEach(function(r){
thin.forEach(function(r){ var pct=Math.round(r.good/r.cnt*100);
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 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 l=document.createElement('span');l.style.color='#f0f6fc';
var v=document.createElement('span');v.textContent=pct+'% reliable';v.style.color=pct<40?'#f85149':'#d29922'; l.textContent=r.state+' — '+r.cnt.toLocaleString()+' workers'+(openSlots?' · '+openSlots+' open slot'+(openSlots>1?'s':''):'');
d.appendChild(l);d.appendChild(v);ins4.appendChild(d); 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); });
} el.appendChild(ins4);
} }
} }