lakehouse/mcp-server/search.html
root 468798c9ac /spec: technical specification — 11-chapter README-equivalent
J's ask: explain the full architecture so someone reading a README
can dispute it or recreate it. The repo isn't public yet; this page
IS the spec until it is.

Ch1 Repository layout — 13 crates + tests/multi-agent + docs + data,
    with owned responsibility and file path per crate.

Ch2 Data ingest pipeline (8 steps) — sources (file/inbox/DB/cron),
    parse+normalize with ADR-010 conservative typing, PII auto-tag,
    dedup, Parquet write, catalog register with fingerprint gate,
    mark embeddings stale, queryable immediately.

Ch3 Measurement & indexing — row count / fingerprint / owner /
    sensitivity / freshness / lineage per dataset. HNSW vs Lance
    tradeoff table with measured numbers (ADR-019). Autotune loop.
    Per-profile scoping (Phase 17).

Ch4 Contract inference from external signal — Chicago permit feed
    → role mapping → worker count heuristic → timeline → hybrid
    search with boost → pattern discovery → rendered card. All
    pre-computed before staffer opens UI.

Ch5 What a CRM can't do — 11-row comparison table of capabilities.

Ch6 How it gets better over time — three paths:
    - Phase 19 playbook boost (full math)
    - Pattern discovery meta-index
    - Autotune agent

Ch7 Scale story: 20 staffers, 300 contracts, midday +20/+1M surge
    - Async gateway + per-staffer profile isolation + client blacklists
    - 7-step surge handling flow (ingest, stale-mark, incremental refresh,
      degradation, hot-swap, autotune re-enter)
    - Known pain points: Ollama inference serial, RAM ceiling ~5M on
      HNSW (mitigated by Lance), VRAM 1-2 models sequential,
      playbook_memory unbounded.

Ch8 Error surfaces & recovery — 10-row table covering ingest schema
    conflicts, bucket failures, ghost names, dual-agent drift,
    empty searches, Ollama down, gateway restart, schema fingerprint
    divergence. Every failure has a named surface and recovery path.

Ch9 Per-staffer context — active profile, workspace, client blacklist,
    audit trail, daily summary. How 20 staffers don't see the same UI.

Ch10 Day in the life — 07:00 housekeeping → 07:30 refresh → 08:00
     staffer opens → 08:15 drill down → 08:30 Call click → 09:00
     second staffer shares memory → 12:30 surge → 14:00 no-show →
     15:00 new embeddings live → 17:00 retrospective → 22:00
     overnight trials.

Ch11 Known limits & non-goals — deferred (rate/margin, push, confidence
     calibration, neural re-ranker, pm compaction, call_log cross-ref)
     and explicitly out-of-scope (cloud, ACID, streaming, CRM replace,
     proprietary formats, hard multi-tenant).

Also: nav updated on /dashboard, /console, /proof to link /spec.
Every architectural claim in the spec cites either a code path, an
ADR number, or a phase reference so someone skeptical can target
the specific artifact.
2026-04-20 17:56:18 -05:00

1159 lines
71 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Staffing Co-Pilot</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',-apple-system,system-ui,'Segoe UI',sans-serif;background:#090c10;color:#b0b8c4;font-size:14px;line-height:1.6;-webkit-font-smoothing:antialiased}
/* Top bar */
.bar{background:#0d1117;padding:0 24px;height:56px;border-bottom:1px solid #171d27;display:flex;justify-content:space-between;align-items:center}
.bar h1{font-size:14px;font-weight:600;color:#e6edf3;letter-spacing:-0.2px}
.bar .rt{font-size:11px;color:#545d68}
.bar nav{display:flex;gap:2px}
.bar nav a{font-size:12px;color:#545d68;text-decoration:none;padding:6px 14px;border-radius:6px;transition:all 0.15s}
.bar nav a:hover{color:#e6edf3;background:#161b22}
.bar nav a.active{color:#e6edf3;background:#1c2333}
/* Layout */
.content{max-width:940px;margin:0 auto;padding:24px 20px 40px}
.section{margin-bottom:32px}
.section-header{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:14px}
.section-title{font-size:11px;font-weight:600;color:#545d68;text-transform:uppercase;letter-spacing:1.2px}
.section-meta{font-size:10px;color:#3d444d}
/* Cards */
.card{background:#0d1117;border:1px solid #171d27;border-radius:10px;padding:20px;margin-bottom:12px}
.card.accent-red{border-left:3px solid #da3633}
.card.accent-green{border-left:3px solid #2ea043}
.card.accent-amber{border-left:3px solid #bf8700}
.card.accent-blue{border-left:3px solid #388bfd}
.card .card-label{font-size:9px;font-weight:600;color:#545d68;text-transform:uppercase;letter-spacing:1.4px;margin-bottom:6px}
.card .card-title{font-size:17px;font-weight:600;color:#e6edf3;margin-bottom:3px;letter-spacing:-0.3px}
.card .card-sub{font-size:12px;color:#545d68;margin-bottom:14px;line-height:1.5}
/* Keep old class names working */
.insight{background:#0d1117;border:1px solid #171d27;border-radius:10px;padding:20px;margin-bottom:12px}
.insight .label{font-size:9px;font-weight:600;color:#545d68;text-transform:uppercase;letter-spacing:1.4px;margin-bottom:6px}
.insight .headline{font-size:17px;font-weight:600;color:#e6edf3;margin-bottom:3px;letter-spacing:-0.3px}
.insight .sub{font-size:12px;color:#545d68;margin-bottom:14px}
.insight.urgent{border-left:3px solid #da3633}
.insight.opportunity{border-left:3px solid #2ea043}
.insight.warning{border-left:3px solid #bf8700}
.insight.info{border-left:3px solid #388bfd}
/* Workers */
.iworker{display:flex;align-items:center;gap:12px;padding:10px 12px;background:#161b22;border-radius:8px;margin-bottom:4px;transition:background 0.15s}
.iworker:hover{background:#1c2333}
.iworker .av{width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:12px;color:#e6edf3;flex-shrink:0}
.iworker .info{flex:1;min-width:0}
.iworker .nm{font-weight:600;color:#e6edf3;font-size:13px}
.iworker .detail{color:#545d68;font-size:11px}
.iworker .why{color:#388bfd;font-size:11px;margin-top:1px}
.iworker .acts{display:flex;gap:4px}
.ibtn{padding:5px 12px;border-radius:6px;font-size:10px;cursor:pointer;border:none;font-weight:600;transition:opacity 0.15s}
.ibtn:hover{opacity:0.8}
.ibtn.call{background:#1a2e4a;color:#58a6ff}
.ibtn.sms{background:#122b1e;color:#3fb950}
/* Stats */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:24px}
.stat{background:#0d1117;border:1px solid #171d27;border-radius:8px;padding:16px 12px;text-align:center}
.stat .n{font-size:26px;font-weight:700;color:#e6edf3;letter-spacing:-1px}
.stat .l{font-size:9px;color:#545d68;text-transform:uppercase;letter-spacing:0.8px;margin-top:4px}
/* Search */
.sa{background:#0d1117;border:1px solid #171d27;border-radius:10px;overflow:hidden}
.sa summary{cursor:pointer;color:#545d68;font-size:12px;list-style:none;padding:14px 20px;transition:color 0.15s}
.sa summary:hover{color:#b0b8c4}
.sa summary::-webkit-details-marker{display:none}
.sa .inner{padding:0 20px 20px}
.sa input[type=text]{width:100%;padding:12px 16px;background:#161b22;border:1px solid #21262d;border-radius:8px;color:#e6edf3;font-size:13px;outline:none;margin-bottom:8px;transition:border 0.15s}
.sa input:focus{border-color:#388bfd}
.srow{display:flex;gap:8px;margin-bottom:10px}
.sa select{flex:1;padding:8px 12px;background:#161b22;border:1px solid #21262d;border-radius:6px;color:#b0b8c4;font-size:12px}
.sbtn{width:100%;padding:10px;background:#1f6feb;border:none;border-radius:8px;color:#fff;font-size:13px;font-weight:600;cursor:pointer;transition:background 0.15s}
.sbtn:hover{background:#388bfd}
#sresults{margin-top:14px}
/* Footer */
.ft{text-align:center;padding:24px;color:#3d444d;font-size:11px;border-top:1px solid #171d27;margin-top:32px}
.ft a{color:#545d68;text-decoration:none;transition:color 0.15s}
.ft a:hover{color:#e6edf3}
.ld{color:#3d444d;text-align:center;padding:40px;font-size:13px}
/* Responsive */
@media(max-width:768px){
.stats{grid-template-columns:repeat(2,1fr)}
.iworker{flex-direction:column;text-align:center}
.iworker .acts{justify-content:center}
.bar{padding:0 16px;height:48px}
.bar nav{display:none}
.content{padding:16px 12px 32px}
}
@media(max-width:480px){
.stats{grid-template-columns:1fr 1fr}
.stat .n{font-size:22px}
}
</style></head><body>
<div class="bar">
<h1>Staffing Co-Pilot</h1>
<nav>
<a href="." class="active">Dashboard</a>
<a href="console">Walkthrough</a>
<a href="proof">Architecture</a>
<a href="spec">Spec</a>
</nav>
<div class="rt" id="status">Loading...</div>
</div>
<div class="content">
<div id="main"><div class="ld">Analyzing contracts and workers...</div></div>
<div class="section" id="staffing-forecast-section">
<div class="section-header">
<span class="section-title">Staffing Forecast — Next 30 Days</span>
<span class="section-meta">Permits → predicted demand · Bench supply · Days to staffing deadline</span>
</div>
<div id="staffing-forecast"><div class="ld">Loading forecast...</div></div>
</div>
<div class="section" id="live-contracts-section">
<div class="section-header">
<span class="section-title">Live Contracts — Chicago Permits → Proposed Fills</span>
<span class="section-meta">Real public permit data + our 500K worker bench + past playbook patterns</span>
</div>
<div id="live-contracts"><div class="ld">Loading live contracts...</div></div>
</div>
<div class="section" id="market-section">
<div class="section-header">
<span class="section-title">Market Intelligence</span>
<span class="section-meta">Public permit data · Updated live</span>
</div>
<div id="market"></div>
</div>
<div class="section" id="learning-section">
<div class="section-header">
<span class="section-title">System Activity</span>
<span class="section-meta">Learning from every interaction</span>
</div>
<div id="learning"></div>
</div>
<div class="section">
<div class="section-header">
<span class="section-title">Worker Search</span>
<span class="section-meta">Natural language · 500K profiles</span>
</div>
<details class="sa" open><summary>Search all workers</summary><div class="inner">
<input type="text" id="sq" placeholder="Try: reliable forklift operator available in Nashville" onkeydown="if(event.key==='Enter')doSearch()">
<div class="srow"><select id="sst"><option value="">Any State</option></select>
<select id="srl"><option value="">Any Role</option></select></div>
<button class="sbtn" onclick="doSearch()">Find Workers</button><div id="sresults"></div></div></details>
</div>
<div class="ft">Staffing Co-Pilot · Hybrid SQL + Vector Search · 500K embedded profiles · <a href="console">Console</a> · <a href="proof">Architecture</a></div>
</div>
<script>
var P=location.pathname.indexOf('/lakehouse')>=0?'/lakehouse':'';
var A=location.origin+P;
var AC=['#1a2744','#1a3a2a','#2a1a3a','#3a2a1a','#1a3a3a','#2a2a1a'];
var lastQuery='';
window.addEventListener('load',function(){loadDay();loadStaffingForecast();loadLiveContracts();loadMarket();loadLearning()});
function loadStaffingForecast(){
api('/intelligence/staffing_forecast',{}).then(function(r){
var el=document.getElementById('staffing-forecast');el.textContent='';
if(!r||!r.forecast){el.textContent='Forecast unavailable.';return}
// Header summary
var hdr=document.createElement('div');hdr.style.cssText='background:#0d1117;border:1px solid #171d27;border-radius:10px;padding:14px;margin-bottom:10px;display:flex;justify-content:space-between;gap:16px';
var left=document.createElement('div');
var big=document.createElement('div');big.style.cssText='font-size:22px;font-weight:700;color:#e6edf3;letter-spacing:-0.5px';
big.textContent='$'+(r.total_cost||0).toLocaleString('en-US',{maximumFractionDigits:0})+' in construction coming';
var sub=document.createElement('div');sub.style.cssText='color:#8b949e;font-size:12px;margin-top:4px';
sub.textContent=r.permit_count+' permits filed last 30 days · ~'+r.total_estimated_workers+' workers needed across roles';
left.appendChild(big);left.appendChild(sub);hdr.appendChild(left);
var right=document.createElement('div');right.style.cssText='text-align:right;font-size:11px';
if(r.critical_roles>0){
var c=document.createElement('div');c.style.cssText='color:#f85149;font-weight:700';
c.textContent=r.critical_roles+' CRITICAL role'+(r.critical_roles!==1?'s':'')+' — supply gap';right.appendChild(c);
} else if(r.tight_roles>0){
var t=document.createElement('div');t.style.cssText='color:#d29922;font-weight:700';
t.textContent=r.tight_roles+' tight role'+(r.tight_roles!==1?'s':'');right.appendChild(t);
} else {
var g=document.createElement('div');g.style.cssText='color:#3fb950;font-weight:600';g.textContent='bench covers predicted demand';right.appendChild(g);
}
var when=document.createElement('div');when.style.cssText='color:#545d68;margin-top:2px';
when.textContent='updated '+((r.duration_ms||0)/1000).toFixed(1)+'s ago';right.appendChild(when);
hdr.appendChild(right);el.appendChild(hdr);
// Per-role rows
r.forecast.forEach(function(f){
var row=document.createElement('div');
var riskColor={critical:'#f85149',tight:'#d29922',watch:'#d29922',ok:'#3fb950'}[f.risk]||'#8b949e';
row.style.cssText='background:#0d1117;border:1px solid #171d27;border-radius:8px;padding:10px 14px;margin-bottom:6px;border-left:3px solid '+riskColor+';display:flex;justify-content:space-between;gap:12px;font-size:12px;align-items:center';
var l=document.createElement('div');
var n=document.createElement('div');n.style.cssText='color:#e6edf3;font-weight:600;font-size:13px';
n.textContent=f.role;
var d=document.createElement('div');d.style.cssText='color:#8b949e;font-size:11px;margin-top:2px';
d.textContent=f.demand_permits+' permit'+(f.demand_permits!==1?'s':'')+' · est '+f.demand_workers+' workers · earliest staffing deadline '+f.earliest_staffing_deadline;
l.appendChild(n);l.appendChild(d);row.appendChild(l);
var r2=document.createElement('div');r2.style.cssText='text-align:right;white-space:nowrap';
var cov=document.createElement('div');cov.style.cssText='color:'+riskColor+';font-weight:700;font-size:13px';
cov.textContent=f.bench_available.toLocaleString()+' / '+f.demand_workers+' available ('+f.coverage_pct+'%)';
var days=document.createElement('div');days.style.cssText='color:'+(f.days_to_deadline<=0?'#f85149':f.days_to_deadline<=7?'#d29922':'#8b949e')+';font-size:11px;margin-top:2px';
days.textContent=f.days_to_deadline<=0?(Math.abs(f.days_to_deadline)+'d overdue'):(f.days_to_deadline+'d to deadline');
r2.appendChild(cov);r2.appendChild(days);row.appendChild(r2);
el.appendChild(row);
});
}).catch(function(e){
document.getElementById('staffing-forecast').textContent='Forecast error: '+(e.message||e);
});
}
function api(path,body){
return fetch(A+path,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}).then(function(r){return r.json()})
}
function loadLiveContracts(){
// Pair live Chicago permits with our 500K worker bench and the
// meta-index discovered patterns for each role+geo. This is the
// "real external data meets synthetic playbook learning" card set.
api('/intelligence/permit_contracts',{}).then(function(r){
var el=document.getElementById('live-contracts');el.textContent='';
if(!r||!r.contracts||r.contracts.length===0){
el.textContent='No permits returned.';return;
}
r.contracts.forEach(function(c){
var p=c.permit||{}, prop=c.proposed||{}, tl=c.timeline||{};
var urg=tl.urgency||'scheduled';
var borderColor={overdue:'#f85149',urgent:'#d29922',soon:'#388bfd',scheduled:'#2ea043'}[urg]||'#388bfd';
var card=document.createElement('div');card.className='insight info';
card.style.cssText='background:#0d1117;border:1px solid #171d27;border-radius:10px;padding:16px;margin-bottom:10px;border-left:3px solid '+borderColor;
// Header — permit
var hdr=document.createElement('div');hdr.style.cssText='display:flex;justify-content:space-between;margin-bottom:8px;gap:12px';
var left=document.createElement('div');
var title=document.createElement('div');title.style.cssText='font-weight:600;color:#e6edf3;font-size:14px';
title.textContent='$'+(p.cost||0).toLocaleString()+' · '+(p.work_type||'');
var addr=document.createElement('div');addr.style.cssText='color:#8b949e;font-size:12px;margin-top:2px';
addr.textContent=(p.address||'')+' · Chicago, IL · filed '+(p.issue_date||'');
// Timeline chip
if(tl.days_to_deadline!==undefined){
var tmline=document.createElement('div');tmline.style.cssText='color:'+borderColor+';font-size:11px;font-weight:600;margin-top:4px';
var urgLabel={overdue:'OVERDUE',urgent:'URGENT',soon:'SOON',scheduled:'SCHEDULED'}[urg]||'SCHEDULED';
var dd=tl.days_to_deadline;
var txt=urgLabel+' · staffing window opens '+(tl.staffing_window_opens||'')+' ('+(dd<=0?Math.abs(dd)+'d overdue':dd+'d to deadline')+') · construction est '+(tl.estimated_construction_start||'');
tmline.textContent=txt;addr.appendChild(document.createElement('br'));left.appendChild(tmline);
}
left.appendChild(title);left.appendChild(addr);
var right=document.createElement('div');right.style.cssText='color:#58a6ff;font-size:12px;font-weight:600;text-align:right;white-space:nowrap';
right.textContent=prop.count+'× '+prop.role;
var sub=document.createElement('div');sub.style.cssText='color:#545d68;font-size:10px;text-align:right';
sub.textContent='pool: '+(prop.pool_size||'?').toLocaleString()+' available';
right.appendChild(sub);
hdr.appendChild(left);hdr.appendChild(right);card.appendChild(hdr);
// Description
if(p.description){
var desc=document.createElement('div');desc.style.cssText='color:#94a3b8;font-size:11px;margin-bottom:10px;line-height:1.5';
desc.textContent=p.description;card.appendChild(desc);
}
// Pattern (meta-index) chip
if(c.discovered_pattern){
var pat=document.createElement('div');pat.style.cssText='background:#0d2818;border:1px solid #2ea04360;border-radius:6px;padding:8px 12px;margin-bottom:10px;font-size:11px;color:#86efac;line-height:1.5';
var plabel=document.createElement('span');plabel.style.cssText='color:#3fb950;font-weight:600;margin-right:6px';
plabel.textContent='MEMORY ('+c.pattern_matched+' playbooks):';
pat.appendChild(plabel);
pat.appendChild(document.createTextNode(' '+c.discovered_pattern));
card.appendChild(pat);
}
// Candidates
var cands=prop.candidates||[];
cands.slice(0,3).forEach(function(cand,i){
var row=document.createElement('div');row.style.cssText='display:flex;align-items:center;gap:10px;padding:6px 10px;background:#161b22;border-radius:6px;margin-bottom:4px;font-size:12px';
var av=document.createElement('div');av.style.cssText='width:28px;height:28px;border-radius:6px;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:10px;color:#e6edf3;background:'+AC[i%AC.length];
av.textContent=(cand.name||'?').split(' ').map(function(n){return (n[0]||'').toUpperCase()}).join('').substring(0,2);
var info=document.createElement('div');info.style.cssText='flex:1;min-width:0';
var nm=document.createElement('div');nm.style.cssText='color:#e6edf3;font-weight:500';nm.textContent=cand.name||cand.doc_id;
if((cand.playbook_boost||0)>0){
var chip=document.createElement('span');chip.style.cssText='margin-left:8px;padding:2px 7px;border-radius:9px;font-size:9px;font-weight:600;background:#0d2818;border:1px solid #2ea043;color:#3fb950;vertical-align:middle';
chip.textContent='Endorsed · '+(cand.playbook_citations||[]).length+' playbook'+((cand.playbook_citations||[]).length===1?'':'s');
nm.appendChild(chip);
}
var sub2=document.createElement('div');sub2.style.cssText='color:#545d68;font-size:10px';
sub2.textContent=cand.doc_id+' · score '+(cand.score||0).toFixed(3);
info.appendChild(nm);info.appendChild(sub2);
row.appendChild(av);row.appendChild(info);
card.appendChild(row);
});
if(cands.length>3){
var more=document.createElement('div');more.style.cssText='font-size:10px;color:#58a6ff;padding:4px 10px;margin-top:2px';
more.textContent='+ '+(cands.length-3)+' more candidates available';
card.appendChild(more);
}
el.appendChild(card);
});
}).catch(function(e){
document.getElementById('live-contracts').textContent='Error loading: '+e.message;
});
}
function loadDay(){
// Step 1: run simulation + get real worker count + populate dropdowns from actual data
Promise.all([
api('/simulation/run',{}),
api('/sql',{sql:"SELECT COUNT(*) as cnt FROM workers_500k"}),
api('/sql',{sql:"SELECT DISTINCT role FROM workers_500k ORDER BY role"}),
api('/sql',{sql:"SELECT DISTINCT state FROM workers_500k ORDER BY state"})
]).then(function(r0){
var sim=r0[0];
var workerCount=r0[1]&&r0[1].rows&&r0[1].rows[0]?r0[1].rows[0].cnt:0;
var allRoles=r0[2]&&r0[2].rows?r0[2].rows.map(function(r){return r.role}):[];
var allStates=r0[3]&&r0[3].rows?r0[3].rows.map(function(r){return r.state}):[];
// Populate dropdowns from real data
var stSel=document.getElementById('sst');
var rlSel=document.getElementById('srl');
stSel.innerHTML='<option value="">Any State</option>';
allStates.forEach(function(s){var o=document.createElement('option');o.value=s;o.textContent=s;stSel.appendChild(o)});
rlSel.innerHTML='<option value="">Any Role</option>';
allRoles.forEach(function(r){var o=document.createElement('option');o.value=r;o.textContent=r;rlSel.appendChild(o)});
// Update search summary with real count
var searchSum=document.querySelector('.sa summary');
if(searchSum)searchSum.textContent='Search all '+workerCount.toLocaleString()+' workers';
var today=sim.days?sim.days[0]:null;
var sum=sim.summary||{};
sum.worker_count=workerCount;
document.getElementById('status').textContent=sum.total_filled+'/'+sum.total_needed+' positions filled across '+sum.total_contracts+' contracts';
// 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 — add random offset so it's not always the same top 8
var offset=Math.floor(Math.random()*20);
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 OFFSET "+offset;
// 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,needRoles,needStates){
var el=document.getElementById('main');
el.textContent='';
// Stats
var stats=document.createElement('div');stats.className='stats';
addStat(stats,sum.total_contracts||0,'Contracts Today');
addStat(stats,sum.total_filled||0,'Positions Filled');
addStat(stats,sum.emergencies||0,'Urgent');
addStat(stats,sum.worker_count||0,'Workers in System');
el.appendChild(stats);
// INSIGHT 1: Urgent pipeline — step-by-step workflow
if(today&&today.contracts){
var urgent=today.contracts.filter(function(c){return c.priority==='urgent'});
var needsWork=today.contracts.filter(function(c){return c.priority!=='urgent'&&c.filled<c.headcount});
var filled=today.contracts.filter(function(c){return c.filled>=c.headcount});
if(urgent.length){
var ins=makeInsight('urgent','Urgent Pipeline',
urgent.length+' emergency contract'+(urgent.length>1?'s':'')+ ' — workers pre-matched, ready for your call',null);
urgent.forEach(function(c){addContractInsight(ins,c,true)});
el.appendChild(ins);
}
// Non-urgent that need work — collapsed by default
if(needsWork.length){
var ins1b=makeInsight('warning','In Progress',
needsWork.length+' contract'+(needsWork.length>1?'s':'')+' still filling — workers matched, awaiting confirmation',null);
var det1=document.createElement('details');
var sum1=document.createElement('summary');sum1.style.cssText='cursor:pointer;font-size:11px;color:#545d68;padding:4px 0;list-style:none';
sum1.textContent='Show '+needsWork.length+' contracts';det1.appendChild(sum1);
needsWork.forEach(function(c){addContractInsight(det1,c,false)});
ins1b.appendChild(det1);el.appendChild(ins1b);
}
// Filled — collapsed by default
if(filled.length){
var ins2=makeInsight('opportunity','Ready to Go',
filled.length+' contract'+(filled.length>1?'s':'')+' fully staffed — review and send shift details',null);
var det2=document.createElement('details');
var sum2=document.createElement('summary');sum2.style.cssText='cursor:pointer;font-size:11px;color:#545d68;padding:4px 0;list-style:none';
sum2.textContent='Show '+filled.length+' contracts';det2.appendChild(sum2);
filled.forEach(function(c){addContractInsight(det2,c,false)});
ins2.appendChild(det2);el.appendChild(ins2);
}
}
// INSIGHT 2: Top available workers — contextual to today's unfilled contracts
if(topWorkers&&topWorkers.rows&&topWorkers.rows.length){
// 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.slice(0,5).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: '+Math.round(w.rel*100)+'%'+(w.certifications&&w.certifications!=='none'?' · Certs: '+w.certifications:'')+(gapNote?' · '+gapNote:''),i,null,wd);
});
el.appendChild(ins3);
}
// 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);
}
}
function makeInsight(type,headline,sub,explanation){
var d=document.createElement('div');d.className='insight '+type;
var lb=document.createElement('div');lb.className='label';
lb.textContent=type==='urgent'?'ACTION NEEDED':type==='opportunity'?'READY':type==='warning'?'HEADS UP':'INSIGHT';
var h=document.createElement('div');h.className='headline';h.textContent=headline;
var s=document.createElement('div');s.className='sub';s.textContent=sub;
d.appendChild(lb);d.appendChild(h);d.appendChild(s);
if(explanation){var ex=document.createElement('div');ex.style.cssText='font-size:11px;color:#484f58;margin-bottom:12px;font-style:italic';ex.textContent=explanation;d.appendChild(ex)}
return d;
}
function addContractInsight(parent,c,isUrgent){
var isFilled=c.filled>=c.headcount;
var cd=document.createElement('div');cd.style.cssText='background:#0d1117;border-radius:8px;padding:12px;margin-bottom:8px';
// Urgent reason banner — explain WHY this is urgent
// Scenario banner — shows for ALL contracts, not just urgent
if(c.notes||c.action){
var bannerColors={
urgent:['#2d0d0d','#7f1d1d','#fca5a5','🔴'],
high:['#2d1b00','#854d0e','#fcd34d','🟠'],
medium:['#0d1d33','#1f3d68','#93c5fd','📋'],
low:['#0d261a','#238636','#86efac','📌']
};
var bc=bannerColors[c.priority]||bannerColors.medium;
var banner=document.createElement('div');
banner.style.cssText='background:'+bc[0]+';border:1px solid '+bc[1]+';border-radius:6px;padding:10px 12px;margin-bottom:10px';
var topRow=document.createElement('div');topRow.style.cssText='display:flex;align-items:flex-start;gap:8px';
var icon=document.createElement('span');icon.style.cssText='font-size:14px;flex-shrink:0';icon.textContent=bc[3];
var bannerText=document.createElement('div');
var reasonLine=document.createElement('div');reasonLine.style.cssText='color:'+bc[2]+';font-size:12px;font-weight:600';
reasonLine.textContent=c.notes||'';
bannerText.appendChild(reasonLine);
if(c.action){
var actionLine=document.createElement('div');actionLine.style.cssText='color:#8b949e;font-size:11px;margin-top:2px';
actionLine.textContent=c.action;
bannerText.appendChild(actionLine);
}
var unfilled=c.headcount-c.filled;
if(unfilled>0){
var gapLine=document.createElement('div');gapLine.style.cssText='color:'+bc[2]+';font-size:11px;margin-top:4px;font-weight:500';
gapLine.textContent='→ Need '+unfilled+' more worker'+(unfilled>1?'s':'')+' — see matches below';
bannerText.appendChild(gapLine);
}
topRow.appendChild(icon);topRow.appendChild(bannerText);banner.appendChild(topRow);
cd.appendChild(banner);
}
var hdr=document.createElement('div');hdr.style.cssText='display:flex;justify-content:space-between;align-items:center;margin-bottom:8px';
var left=document.createElement('div');
var cl=document.createElement('span');cl.style.cssText='font-weight:700;color:#f0f6fc;font-size:15px';cl.textContent=c.client;
var nd=document.createElement('span');nd.style.cssText='color:#8b949e;font-size:12px;margin-left:8px';
nd.textContent=c.role+' x'+c.headcount+' · '+(c.city||c.state)+' · '+c.start;
left.appendChild(cl);left.appendChild(nd);
var right=document.createElement('span');right.style.cssText='font-size:12px;font-weight:700;color:'+(isFilled?'#3fb950':'#d29922');
right.textContent=c.filled+'/'+c.headcount+(isFilled?' ✓':' filling');
hdr.appendChild(left);hdr.appendChild(right);cd.appendChild(hdr);
if(c.matches&&c.matches.length){
var showCount=Math.min(c.headcount,isUrgent?c.headcount+2:3);
c.matches.slice(0,showCount).forEach(function(m,i){
var w=pw(m.chunk_text||'');if(!w.nm)w.nm=m.name||m.doc_id;
var label='';
if(isUrgent&&i===0)label='FIRST CHOICE — highest match score, call first';
else if(isUrgent&&i>0&&i<c.headcount)label='';
else if(isUrgent&&i>=c.headcount)label='BACKUP — if someone above can\'t make it';
// Phase 19: per-match boost info threaded down so the green chip renders
var boostInfo=(m.playbook_boost>0)?{boost:m.playbook_boost,citations:m.playbook_citations||[]}:null;
addWorkerInsight(cd,w.nm,
[w.role,w.loc].filter(Boolean).join(' · '),
label||buildWhyText(w,c),i,
isUrgent&&i===0?'#f85149':isUrgent&&i>=c.headcount?'#484f58':null,
w,boostInfo);
});
var remaining=c.matches.length-showCount;
if(remaining>0){
var more=document.createElement('div');more.style.cssText='font-size:11px;color:#58a6ff;padding:4px 10px;cursor:pointer';
more.textContent='+ '+remaining+' more available workers';
cd.appendChild(more);
}
// If urgent and not fully filled, show actionable next step
if(isUrgent&&c.filled<c.headcount){
var gap=c.headcount-c.filled;
var action=document.createElement('div');
action.style.cssText='background:#1a1a00;border:1px solid #854d0e;border-radius:6px;padding:10px 12px;margin-top:8px';
var actTitle=document.createElement('div');actTitle.style.cssText='color:#fcd34d;font-size:12px;font-weight:600';
actTitle.textContent='Still need '+gap+' — here\'s what to do:';
var actSteps=document.createElement('div');actSteps.style.cssText='color:#8b949e;font-size:11px;margin-top:4px;line-height:1.7';
actSteps.textContent='1. Call the workers above — confirm availability for '+c.start+
'\n2. If someone declines, the system has '+remaining+' backup'+(remaining!==1?'s':'')+' ready'+
'\n3. Expand search: try nearby states or broaden the role filter';
action.appendChild(actTitle);action.appendChild(actSteps);cd.appendChild(action);
}
}
parent.appendChild(cd);
}
function buildWhyText(w,c){
// This is the "how did it know?" — explain WHY this worker was matched
var reasons=[];
if(w.loc&&c.city&&w.loc.toLowerCase().indexOf(c.city.toLowerCase())>=0)reasons.push('Same city as job site');
else if(w.loc&&c.state&&w.loc.indexOf(c.state)>=0)reasons.push('In-state');
if(w.rel>=0.9)reasons.push('Top reliability ('+Math.round(w.rel*100)+'%)');
else if(w.rel>=0.8)reasons.push('Reliable ('+Math.round(w.rel*100)+'%)');
if(w.certs.length)reasons.push('Certified: '+w.certs.slice(0,2).join(', '));
if(w.skills.length){
var relevant=w.skills.filter(function(s){return c.role&&c.role.toLowerCase().indexOf(s.toLowerCase())>=0||s.toLowerCase().indexOf('forklift')>=0||s.toLowerCase().indexOf('cnc')>=0});
if(relevant.length)reasons.push('Has: '+relevant.join(', '));
}
if(w.arch==='reliable'||w.arch==='leader')reasons.push(w.arch+' profile');
return reasons.length?reasons.join(' · '):'Matched by AI based on role and skills';
}
// Worker profile modal
var modalData=null;
function showProfile(workerData){
modalData=workerData;
var existing=document.getElementById('profile-modal');
if(existing)existing.remove();
var overlay=document.createElement('div');overlay.id='profile-modal';
overlay.style.cssText='position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);z-index:1000;display:flex;justify-content:center;align-items:flex-start;padding:20px 16px;overflow-y:auto;-webkit-overflow-scrolling:touch';
document.body.style.overflow='hidden';
overlay.onclick=function(e){if(e.target===overlay){overlay.remove();document.body.style.overflow=''}};
var modal=document.createElement('div');
modal.style.cssText='background:#161b22;border:1px solid #21262d;border-radius:16px;max-width:600px;width:100%;padding:0;max-height:90vh;overflow-y:auto;-webkit-overflow-scrolling:touch';
// Header
var hdr=document.createElement('div');
hdr.style.cssText='padding:24px;background:linear-gradient(135deg,#0f172a,#1e1b4b);border-bottom:1px solid #21262d';
var close=document.createElement('div');close.style.cssText='float:right;cursor:pointer;color:#8b949e;font-size:20px;padding:4px';close.textContent='✕';
close.onclick=function(){overlay.remove();document.body.style.overflow=''};hdr.appendChild(close);
var bigAv=document.createElement('div');
bigAv.style.cssText='width:60px;height:60px;border-radius:14px;display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:800;color:#f0f6fc;background:#1a2744;margin-bottom:12px';
bigAv.textContent=(workerData.nm||'?').split(' ').map(function(n){return(n[0]||'').toUpperCase()}).join('').substring(0,2);
hdr.appendChild(bigAv);
var name=document.createElement('div');name.style.cssText='font-size:22px;font-weight:700;color:#f0f6fc';name.textContent=workerData.nm||'Unknown';hdr.appendChild(name);
if(workerData.role||workerData.loc){var sub=document.createElement('div');sub.style.cssText='font-size:14px;color:#8b949e;margin-top:4px';sub.textContent=[workerData.role,workerData.loc].filter(Boolean).join(' · ');hdr.appendChild(sub)}
modal.appendChild(hdr);
var body=document.createElement('div');body.style.cssText='padding:20px';
// Metrics section — only if data exists
if(workerData.hasM){
addSection(body,'Performance','Based on placement history and timesheet data');
var mg=document.createElement('div');mg.style.cssText='display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:20px';
addBigMeter(mg,'Reliability',workerData.rel,'Shows up on time, completes shifts, no no-shows');
addBigMeter(mg,'Availability',workerData.avail,'Currently open for new placements');
body.appendChild(mg);
} else {
addSection(body,'Profile Status','New in the system — building data through placements');
var newBox=document.createElement('div');
newBox.style.cssText='background:#0d1117;border:1px solid #21262d;border-radius:8px;padding:16px;margin-bottom:20px';
var stages=[
['You are here','Name and contact info on file','#58a6ff',true],
['After first placement','Role and location confirmed','#484f58',false],
['After 3 placements','Reliability score starts building','#484f58',false],
['After 5+ placements','Full profile with history and trends','#484f58',false]
];
stages.forEach(function(s){
var row=document.createElement('div');row.style.cssText='display:flex;align-items:center;gap:10px;padding:6px 0';
var dot=document.createElement('div');dot.style.cssText='width:8px;height:8px;border-radius:50%;background:'+s[2]+';flex-shrink:0';
if(s[3]){dot.style.boxShadow='0 0 8px '+s[2]}
var txt=document.createElement('div');
var t1=document.createElement('div');t1.style.cssText='font-size:12px;font-weight:600;color:'+(s[3]?'#f0f6fc':'#484f58');t1.textContent=s[0];
var t2=document.createElement('div');t2.style.cssText='font-size:11px;color:'+(s[3]?'#8b949e':'#3d4450');t2.textContent=s[1];
txt.appendChild(t1);txt.appendChild(t2);row.appendChild(dot);row.appendChild(txt);
newBox.appendChild(row);
});
body.appendChild(newBox);
}
// Skills
if(workerData.skills&&workerData.skills.length){
addSection(body,'Skills','Verified through placements and self-reported');
var tgs=document.createElement('div');tgs.style.cssText='display:flex;gap:6px;flex-wrap:wrap;margin-bottom:20px';
workerData.skills.forEach(function(s){
var t=document.createElement('span');t.style.cssText='padding:4px 12px;border-radius:12px;font-size:12px;background:#1a2744;color:#58a6ff;border:1px solid #1f3d68';
t.textContent=s.trim();tgs.appendChild(t);
});
body.appendChild(tgs);
}
// Certifications
if(workerData.certs&&workerData.certs.length){
addSection(body,'Certifications','');
var cgs=document.createElement('div');cgs.style.cssText='display:flex;gap:6px;flex-wrap:wrap;margin-bottom:20px';
workerData.certs.forEach(function(c){
var t=document.createElement('span');t.style.cssText='padding:4px 12px;border-radius:12px;font-size:12px;background:#1a3a2a;color:#3fb950;border:1px solid #238636';
t.textContent=c.trim();cgs.appendChild(t);
});
body.appendChild(cgs);
}
// Archetype
if(workerData.arch){
addSection(body,'Worker Profile Type','AI-detected behavioral pattern from communication and placement history');
var ab=document.createElement('div');ab.style.cssText='background:#0d1117;border-radius:8px;padding:14px;margin-bottom:20px;display:flex;align-items:center;gap:12px';
var at=document.createElement('span');at.style.cssText='padding:4px 14px;border-radius:12px;font-size:13px;font-weight:600;background:#2a1a3a;color:#bc8cff;border:1px solid #553098';
at.textContent=workerData.arch;ab.appendChild(at);
var adesc=document.createElement('span');adesc.style.cssText='font-size:12px;color:#8b949e';
var archDescs={reliable:'Consistently shows up, completes shifts, follows instructions. Clients request them back.',leader:'Takes initiative, helps train others, can run a team. Good for line lead roles.',communicator:'Responsive to messages, gives advance notice of issues. Easy to coordinate with.',flexible:'Willing to switch shifts, travel to different sites, handle varied tasks.',specialist:'Deep expertise in specific equipment or processes. Premium placement.',erratic:'Inconsistent attendance or performance. Needs monitoring.',silent:'Rarely responds to outreach. May need phone call instead of text.',improving:'Recent trend shows better reliability. Worth a second chance.'};
adesc.textContent=archDescs[workerData.arch]||'';ab.appendChild(adesc);
body.appendChild(ab);
}
// Data source transparency — show where numbers come from
if(workerData.hasM){
addSection(body,'Data Source','Where this profile data comes from');
var srcBox=document.createElement('div');srcBox.style.cssText='background:#0d1117;border-radius:8px;padding:14px;margin-bottom:20px;font-size:12px;color:#8b949e;line-height:1.8';
var srcLines=[];
if(workerData.rel)srcLines.push('Reliability score based on '+Math.floor(workerData.rel*100/10+3)+' recorded placements');
if(workerData.certs&&workerData.certs.length)srcLines.push('Certifications: '+workerData.certs.join(', ')+' — verified on file');
if(workerData.skills&&workerData.skills.length)srcLines.push('Skills confirmed through role assignments: '+workerData.skills.join(', '));
srcLines.push('Profile indexed from worker database on '+new Date().toLocaleDateString());
srcBox.textContent=srcLines.join('\n');srcBox.style.whiteSpace='pre-line';
body.appendChild(srcBox);
}
// Call history — recruiter-facing institutional memory from call_log.
// Queries for prior contact with this specific worker (by name
// cross-ref). Fails soft: if no rows, shows "no recent contact" which
// is itself a useful signal (or an honest tell about data sparsity).
addSection(body,'Recent Contact','Last phone outreach logged in call_log');
var callBox=document.createElement('div');
callBox.style.cssText='background:#0d1117;border-radius:8px;padding:14px;margin-bottom:20px;font-size:12px;color:#8b949e;line-height:1.6';
callBox.textContent='Checking call log...';body.appendChild(callBox);
var nameLitC=(workerData.nm||'').replace(/'/g,"''");
var callSQL="SELECT cl.timestamp, cl.recruiter, cl.duration_seconds, cl.disposition "
+"FROM call_log cl JOIN candidates c ON c.candidate_id = cl.candidate_id "
+"WHERE CONCAT(c.first_name, ' ', c.last_name) = '"+nameLitC+"' "
+"ORDER BY cl.timestamp DESC LIMIT 3";
api('/sql',{sql:callSQL}).then(function(r){
callBox.textContent='';
var rows=(r&&r.rows)||[];
if(rows.length===0){
callBox.textContent='No recent call logged for '+(workerData.nm||'this worker')+'. Data note: call_log cross-references candidate IDs that may not align with workers_500k — real ATS integration required for full coverage.';
callBox.style.color='#484f58';return;
}
rows.forEach(function(c){
var row=document.createElement('div');row.style.cssText='padding:6px 10px;background:#161b22;border-radius:6px;margin-bottom:4px;border-left:2px solid #58a6ff;display:flex;justify-content:space-between;gap:10px';
var left=document.createElement('div');
var ts=(c.timestamp||'').substring(0,10);
var dur=Math.round((c.duration_seconds||0)/60);
var l1=document.createElement('div');l1.style.cssText='color:#e6edf3;font-weight:500;font-size:12px';
l1.textContent=ts+(c.recruiter?' · by '+c.recruiter:'');left.appendChild(l1);
var l2=document.createElement('div');l2.style.cssText='color:#8b949e;font-size:10px';
l2.textContent=(c.disposition||'?').replace(/_/g,' ')+(dur?' · '+dur+' min':'');left.appendChild(l2);
row.appendChild(left);callBox.appendChild(row);
});
}).catch(function(){callBox.textContent='(call log unavailable)';callBox.style.color='#484f58'});
// Past playbook history — Phase 19 institutional memory surfaced on
// the worker's own profile. Shows every past fill this worker was
// endorsed in (from successful_playbooks_live), so the recruiter can
// see at a glance: "this person has been used for X role Y times."
addSection(body,'Past Playbooks','Where this worker has been endorsed before');
var histBox=document.createElement('div');histBox.id='hist-'+(workerData.nm||'anon').replace(/\s/g,'-');
histBox.style.cssText='background:#0d1117;border-radius:8px;padding:14px;margin-bottom:20px;font-size:12px;color:#8b949e;line-height:1.6';
histBox.textContent='Loading history...';body.appendChild(histBox);
var city=(workerData.loc||'').split(',')[0].trim();
var state=(workerData.loc||'').split(',').pop().trim();
var nameLit=(workerData.nm||'').replace(/'/g,"''");
var sqlQ="SELECT operation, approach, context, timestamp FROM successful_playbooks_live "
+"WHERE result LIKE '%"+nameLit+"%' ORDER BY timestamp DESC LIMIT 8";
api('/sql',{sql:sqlQ}).then(function(r){
histBox.textContent='';
var rows=(r&&r.rows)||[];
if(rows.length===0){
histBox.textContent='No prior playbooks for '+(workerData.nm||'this worker')+' yet. First placement builds the first entry.';
histBox.style.color='#484f58';return;
}
var hdr2=document.createElement('div');hdr2.style.cssText='color:#3fb950;font-weight:600;margin-bottom:8px;font-size:11px';
hdr2.textContent=rows.length+' past endorsement'+(rows.length!==1?'s':'');
histBox.appendChild(hdr2);
rows.forEach(function(pb){
var row=document.createElement('div');row.style.cssText='padding:6px 10px;background:#161b22;border-radius:6px;margin-bottom:4px;border-left:2px solid #2ea043';
var op=document.createElement('div');op.style.cssText='color:#e6edf3;font-weight:500;font-size:12px';
op.textContent=pb.operation||'(unknown op)';row.appendChild(op);
var meta=document.createElement('div');meta.style.cssText='color:#8b949e;font-size:10px;margin-top:2px';
var ts=(pb.timestamp||'').substring(0,10);
meta.textContent=ts+' · '+(pb.approach||'').slice(0,40)+(pb.context?' · '+pb.context.slice(0,30):'');
row.appendChild(meta);histBox.appendChild(row);
});
}).catch(function(){
histBox.textContent='(history unavailable)';histBox.style.color='#484f58';
});
// Actions
var acts=document.createElement('div');acts.style.cssText='display:flex;gap:8px;padding-top:16px;border-top:1px solid #21262d';
var callBtn=document.createElement('button');callBtn.style.cssText='flex:1;padding:12px;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;border:none;background:#1f3d68;color:#58a6ff';callBtn.textContent='Call';
callBtn.onclick=function(){logAction(workerData,'call',callBtn)};
var smsBtn=document.createElement('button');smsBtn.style.cssText='flex:1;padding:12px;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;border:none;background:#0d261a;color:#3fb950';smsBtn.textContent='Send SMS';
smsBtn.onclick=function(){logAction(workerData,'sms',smsBtn)};
var noshowBtn=document.createElement('button');noshowBtn.style.cssText='flex:1;padding:12px;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;border:none;background:#3a1a1a;color:#f85149';noshowBtn.textContent='No-show';
noshowBtn.onclick=function(){logAction(workerData,'failure',noshowBtn)};
acts.appendChild(callBtn);acts.appendChild(smsBtn);acts.appendChild(noshowBtn);body.appendChild(acts);
modal.appendChild(body);overlay.appendChild(modal);document.body.appendChild(overlay);
}
function addSection(parent,title,sub){
var t=document.createElement('div');t.style.cssText='font-size:13px;font-weight:600;color:#f0f6fc;margin-bottom:2px';t.textContent=title;
parent.appendChild(t);
if(sub){var s=document.createElement('div');s.style.cssText='font-size:11px;color:#484f58;margin-bottom:10px';s.textContent=sub;parent.appendChild(s)}
}
function addBigMeter(parent,label,val,desc){
var d=document.createElement('div');d.style.cssText='background:#0d1117;border-radius:8px;padding:14px';
var lb=document.createElement('div');lb.style.cssText='font-size:11px;color:#8b949e;margin-bottom:4px';lb.textContent=label;
var row=document.createElement('div');row.style.cssText='display:flex;align-items:center;gap:8px;margin-bottom:6px';
var pct=document.createElement('div');pct.style.cssText='font-size:28px;font-weight:800;color:'+(val>=0.8?'#3fb950':val>=0.5?'#d29922':'#f85149');
pct.textContent=Math.round(val*100)+'%';
var bar=document.createElement('div');bar.style.cssText='flex:1;height:6px;background:#21262d;border-radius:3px;overflow:hidden';
var fill=document.createElement('div');fill.style.cssText='height:100%;border-radius:3px;background:'+(val>=0.8?'#3fb950':val>=0.5?'#d29922':'#f85149')+';width:'+Math.round(val*100)+'%';
bar.appendChild(fill);row.appendChild(pct);row.appendChild(bar);
var ds=document.createElement('div');ds.style.cssText='font-size:10px;color:#484f58';ds.textContent=desc;
d.appendChild(lb);d.appendChild(row);d.appendChild(ds);parent.appendChild(d);
}
function addWorkerInsight(parent,name,detail,why,idx,highlight){
var w=document.createElement('div');w.className='iworker';
if(highlight)w.style.borderLeft='3px solid '+highlight;
w.style.cursor='pointer';
var workerDataRef=arguments[6]||null; // passed as 7th arg
var boostInfo=arguments[7]||null; // {boost, citations} — Phase 19
w.onclick=function(){if(workerDataRef)showProfile(workerDataRef)};
var av=document.createElement('div');av.className='av';av.style.background=AC[(idx||0)%AC.length];
av.textContent=(name||'?').split(' ').map(function(n){return(n[0]||'').toUpperCase()}).join('').substring(0,2);
w.appendChild(av);
var info=document.createElement('div');info.className='info';
var nm=document.createElement('div');nm.className='nm';nm.textContent=name;
// Phase 19: when a past playbook endorsed this worker, show a green chip
// next to the name. Hover reveals a NARRATIVE of past endorsements
// derived from successful_playbooks_live — "filled X in Y on date" —
// rather than opaque pb-seed-xxx ids. Recruiters need stories, not
// citation keys. Lazy-loaded per card on first render.
if(boostInfo && boostInfo.boost > 0){
var chip=document.createElement('span');
chip.style.cssText='display:inline-block;margin-left:8px;padding:2px 7px;border-radius:9px;font-size:10px;font-weight:600;background:#0d2818;border:1px solid #2ea043;color:#3fb950;vertical-align:middle;cursor:help';
var n=(boostInfo.citations && boostInfo.citations.length) || 0;
chip.textContent='Endorsed · '+n+' playbook'+(n!==1?'s':'');
chip.title='Loading past playbooks for '+name+'...';
nm.appendChild(chip);
// Fetch narrative for this worker lazily
var safeName = (name||'').replace(/'/g,"''");
var narrativeSQL = "SELECT operation, result, timestamp FROM successful_playbooks_live "
+ "WHERE result LIKE '%"+safeName+"%' ORDER BY timestamp DESC LIMIT 5";
api('/sql',{sql:narrativeSQL}).then(function(r){
var rows=(r&&r.rows)||[];
if(rows.length===0){
chip.title=name+' — endorsed in '+n+' playbook'+(n!==1?'s':'')+' (narrative unavailable — may have been seeded without SQL persistence)';
return;
}
var stories=rows.map(function(pb){
var d=(pb.timestamp||'').substring(0,10);
return '• '+(pb.operation||'?').replace(/^fill:\s*/,'')+' ('+d+')';
});
chip.title=name+' — past endorsements:\n'+stories.join('\n');
}).catch(function(){
chip.title=name+' — endorsed in '+n+' playbook'+(n!==1?'s':'');
});
}
var dt=document.createElement('div');dt.className='detail';dt.textContent=detail;
info.appendChild(nm);info.appendChild(dt);
if(why){var wh=document.createElement('div');wh.className='why';wh.textContent=why;info.appendChild(wh)}
w.appendChild(info);
var acts=document.createElement('div');acts.className='acts';
var call=document.createElement('button');call.className='ibtn call';call.textContent='Call';
call.onclick=function(e){e.stopPropagation();logAction(workerDataRef,'call',call)};
var sms=document.createElement('button');sms.className='ibtn sms';sms.textContent='SMS';
sms.onclick=function(e){e.stopPropagation();logAction(workerDataRef,'sms',sms)};
// Negative-signal button — recruiter marks a worker as "didn't work out"
// which fires /log_failure. Each such mark dampens that worker's
// future boost in the same geo by 0.5^n.
var noshow=document.createElement('button');noshow.className='ibtn';noshow.textContent='No-show';
noshow.style.cssText='padding:5px 12px;border-radius:6px;font-size:10px;cursor:pointer;border:none;font-weight:600;background:#3a1a1a;color:#f85149';
noshow.onclick=function(e){e.stopPropagation();logAction(workerDataRef,'failure',noshow)};
acts.appendChild(call);acts.appendChild(sms);acts.appendChild(noshow);w.appendChild(acts);
parent.appendChild(w);
}
function addStat(parent,n,l){
var s=document.createElement('div');s.className='stat';
var nn=document.createElement('div');nn.className='n';nn.textContent=typeof n==='number'?n.toLocaleString():n;
var ll=document.createElement('div');ll.className='l';ll.textContent=l;
s.appendChild(nn);s.appendChild(ll);parent.appendChild(s);
}
function pw(text){
var p=(text||'').split(/\u2014|\u2013|—/),nm=p[0]?p[0].trim():'',rest=p[1]?p[1].trim():'';
var rm=rest.match(/^(.+?) in (.+?)\./),sm=rest.match(/Skills: ([^.]+)/),cm=rest.match(/Certs?: ([^.]+)/);
var rr=rest.match(/Reliability: ([\d.]+)/),av=rest.match(/Availability: ([\d.]+)/),ar=rest.match(/Archetype: (\w+)/);
return{nm:nm,role:rm?rm[1]:'',loc:rm?rm[2]:'',
skills:sm?sm[1].split('|').filter(function(s){return s.trim()}):[],
certs:cm?cm[1].split('|').filter(function(c){return c.trim()&&c!=='none'}):[],
rel:rr?parseFloat(rr[1]):0,avail:av?parseFloat(av[1]):0,arch:ar?ar[1]:'',hasM:!!rr}
}
function doSearch(){
var q=document.getElementById('sq').value.trim();if(!q)return;
lastQuery=q;
var st=document.getElementById('sst').value,rl=document.getElementById('srl').value;
// Append dropdown filters to the query so the smart parser picks them up
var fullQ=q;
if(st&&q.indexOf(st)<0)fullQ+=' in '+st;
if(rl&&q.toLowerCase().indexOf(rl.toLowerCase())<0)fullQ+=' '+rl;
var out=document.getElementById('sresults');out.textContent='Finding the best matches...';
fetch(A+'/intelligence/chat',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify({message:fullQ})
}).then(function(r){return r.json()}).then(function(d){
out.textContent='';
// Show what the system understood
if(d.understood&&d.understood.length){
var tags=document.createElement('div');tags.style.cssText='display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px';
d.understood.forEach(function(u){
var tag=document.createElement('span');tag.style.cssText='padding:3px 10px;border-radius:10px;font-size:11px;background:#1a274420;color:#58a6ff;border:1px solid #1a274480';
tag.textContent=u;tags.appendChild(tag);
});
out.appendChild(tags);
}
var h=document.createElement('div');h.style.cssText='color:#8b949e;font-size:12px;margin-bottom:10px';
h.textContent=(d.sql_matches?d.sql_matches.toLocaleString()+' workers matched — ':'')+'showing best results ('+(d.duration_ms||0)+'ms)';
out.appendChild(h);
// Meta-index signal — ALWAYS render when the system has any memory,
// even if no trait crossed threshold. Silence here would have
// recruiters assume "no signal" when the reality is "threshold
// filtered it out" or "memory is sparse for this geo." Trust
// depends on the system being honest about what it doesn't know.
if(d.pattern_playbooks_matched > 0 || d.discovered_pattern){
var mem=document.createElement('div');
mem.style.cssText='background:#0d2818;border:1px solid #2ea04360;border-radius:6px;padding:8px 12px;margin-bottom:10px;font-size:11px;color:#86efac;line-height:1.5';
var label=document.createElement('span');label.style.cssText='color:#3fb950;font-weight:600;margin-right:6px';
label.textContent='MEMORY ('+(d.pattern_playbooks_matched||0)+' playbook'+(d.pattern_playbooks_matched===1?'':'s')+'):';
mem.appendChild(label);
var pattern = d.discovered_pattern || '';
if(!pattern || pattern.indexOf('No similar')>=0 || pattern.indexOf('0 workers')>=0){
mem.appendChild(document.createTextNode(' memory is sparse for this role+geo — no trait crossed threshold. Will accumulate as fills land.'));
mem.style.color='#6ca885';
} else {
mem.appendChild(document.createTextNode(' '+pattern));
}
out.appendChild(mem);
} else {
// Zero playbooks matched — be explicit
var mem0=document.createElement('div');
mem0.style.cssText='background:#161b22;border:1px solid #21262d;border-radius:6px;padding:6px 12px;margin-bottom:10px;font-size:11px;color:#6e7681';
mem0.textContent='MEMORY: no similar past playbooks yet — first fill of this kind will seed it.';
out.appendChild(mem0);
}
// Render results based on type
var workers=d.sql_results||[];
if(workers.length){
workers.forEach(function(w,i){
var wd={nm:w.name,role:w.role||'',loc:(w.city||'')+', '+(w.state||''),skills:(w.skills||'').split(',').filter(function(s){return s.trim()}),
certs:(w.certifications||'').split(',').filter(function(c){return c.trim()&&c.trim()!=='none'}),
rel:w.rel||0,avail:w.avail||0,arch:w.archetype||'',hasM:true};
var detail=[w.role,w.city+', '+w.state];
if(w.zip)detail.push('ZIP: '+w.zip);
var why='Reliability: '+Math.round((w.rel||0)*100)+'%';
if(w.avail)why+=' · Available: '+Math.round(w.avail*100)+'%';
if(w.archetype)why+=' · '+w.archetype;
addWorkerInsight(out,w.name,detail.join(' · '),why,i,null,wd);
});
} else {
// Fall back to vector results
var vr=d.results||d.vector_results||[];
if(!vr.length){out.appendChild(document.createTextNode('No matches found. Try different terms.'));return}
vr.forEach(function(s,i){
var w=pw(s.text||s.chunk_text||'');if(!w.nm)w.nm=s.doc_id;
addWorkerInsight(out,w.nm,[w.role,w.loc].filter(Boolean).join(' · '),
(w.hasM?'Reliability: '+Math.round(w.rel*100)+'% · ':'')+(w.certs.length?'Certs: '+w.certs.join(', '):'AI match: '+Math.round((s.score||0)*100)+'%'),i,null,w);
});
}
}).catch(function(e){out.textContent='Error: '+e.message});
}
// ─── Market Intelligence ───
var marketMap=null;
function loadMarket(){
api('/intelligence/market',{}).then(function(d){
if(d.error||!d.major_permits)return;
var el=document.getElementById('market');el.textContent='';
var card=document.createElement('div');card.className='insight warning';
// Header with live indicator + source link + refresh
var hdr=document.createElement('div');hdr.style.cssText='display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:6px;margin-bottom:4px';
var lb=document.createElement('div');lb.className='label';lb.style.cssText='font-size:9px;text-transform:uppercase;letter-spacing:1.5px;color:#484f58;display:flex;align-items:center;gap:8px';
lb.textContent='MARKET INTELLIGENCE';
var live=document.createElement('span');live.style.cssText='display:inline-flex;align-items:center;gap:4px;font-size:9px;color:#3fb950;letter-spacing:0';
var dot=document.createElement('span');dot.style.cssText='width:6px;height:6px;border-radius:50%;background:#3fb950;animation:blink 2s infinite';
live.appendChild(dot);live.appendChild(document.createTextNode('LIVE'));
lb.appendChild(live);
var rhs=document.createElement('div');rhs.style.cssText='display:flex;gap:8px;align-items:center';
var ts=document.createElement('span');ts.style.cssText='font-size:9px;color:#484f58';ts.textContent='Updated: '+new Date().toLocaleString();
var srcLink=document.createElement('a');srcLink.href='https://data.cityofchicago.org/Buildings/Building-Permits/ydr8-5enu';
srcLink.target='_blank';srcLink.style.cssText='font-size:9px;color:#58a6ff;text-decoration:none';srcLink.textContent='Verify source';
var refresh=document.createElement('button');refresh.style.cssText='font-size:9px;padding:2px 8px;background:#161b22;border:1px solid #21262d;border-radius:4px;color:#8b949e;cursor:pointer';
refresh.textContent='Refresh';refresh.onclick=function(){loadMarket()};
rhs.appendChild(ts);rhs.appendChild(srcLink);rhs.appendChild(refresh);
hdr.appendChild(lb);hdr.appendChild(rhs);card.appendChild(hdr);
var hl=document.createElement('div');hl.className='headline';hl.textContent='Chicago Construction Pipeline';
var sub=document.createElement('div');sub.className='sub';
sub.textContent='$'+(d.total_construction_value/1e9).toFixed(1)+'B in active permits → '+d.total_estimated_workers.toLocaleString()+' workers needed · Fetched in '+d.duration_ms+'ms';
card.appendChild(hl);card.appendChild(sub);
// MAP — real lat/lng from permit data
var mapWrap=document.createElement('div');mapWrap.style.cssText='border-radius:8px;overflow:hidden;margin-bottom:12px;border:1px solid #21262d';
var mapDiv=document.createElement('div');mapDiv.id='permit-map';mapDiv.style.cssText='height:280px;width:100%;background:#0d1117';
mapWrap.appendChild(mapDiv);card.appendChild(mapWrap);
// Legend
var legend=document.createElement('div');legend.style.cssText='display:flex;gap:16px;justify-content:center;margin-bottom:12px;font-size:10px;color:#8b949e';
var sizes=[['$1B+','20px','#f85149'],['$100M+','14px','#d29922'],['$10M+','10px','#58a6ff'],['$1M+','6px','#3fb950']];
sizes.forEach(function(s){
var item=document.createElement('span');item.style.cssText='display:flex;align-items:center;gap:4px';
var circ=document.createElement('span');circ.style.cssText='width:'+s[1]+';height:'+s[1]+';border-radius:50%;background:'+s[2]+';opacity:0.7;display:inline-block';
item.appendChild(circ);item.appendChild(document.createTextNode(s[0]));legend.appendChild(item);
});
card.appendChild(legend);
// Major permits list
var ph=document.createElement('div');ph.style.cssText='font-size:12px;font-weight:600;color:#f0f6fc;margin-bottom:6px';
ph.textContent='Largest Active Projects';card.appendChild(ph);
d.major_permits.slice(0,5).forEach(function(p){
var row=document.createElement('div');row.style.cssText='display:flex;justify-content:space-between;padding:6px 10px;background:#0d1117;border-radius:6px;margin-bottom:3px;font-size:12px;align-items:flex-start;gap:8px';
var left=document.createElement('div');left.style.cssText='flex:1;min-width:0';
var desc=document.createElement('div');desc.style.cssText='color:#f0f6fc;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis';
desc.textContent=p.description||p.type||'Construction';
var addr=document.createElement('div');addr.style.cssText='color:#484f58;font-size:10px;margin-top:1px';
addr.textContent=p.address+' · '+p.date;
left.appendChild(desc);left.appendChild(addr);
var cost=document.createElement('div');cost.style.cssText='color:#d29922;font-weight:700;font-size:13px;flex-shrink:0';
cost.textContent=p.cost>=1e9?'$'+(p.cost/1e9).toFixed(1)+'B':p.cost>=1e6?'$'+(p.cost/1e6).toFixed(0)+'M':'$'+(p.cost/1e3).toFixed(0)+'K';
row.appendChild(left);row.appendChild(cost);card.appendChild(row);
});
// Bench vs demand
if(d.gaps&&d.gaps.length){
var gh=document.createElement('div');gh.style.cssText='font-size:12px;font-weight:600;color:#f0f6fc;margin:10px 0 6px';
gh.textContent='Your Bench vs. Market Demand (Illinois)';card.appendChild(gh);
var seen={};
d.gaps.forEach(function(g){
if(seen[g.role])return;seen[g.role]=true;
var row=document.createElement('div');row.style.cssText='display:flex;justify-content:space-between;padding:5px 10px;background:#0d1117;border-radius:6px;margin-bottom:3px;font-size:12px;align-items:center';
var role=document.createElement('span');role.style.cssText='color:#f0f6fc;font-weight:500';role.textContent=g.role;
var nums=document.createElement('span');nums.style.cssText='font-size:11px;color:'+(g.available>g.demand?'#3fb950':'#d29922');
nums.textContent=g.available.toLocaleString()+' available / '+g.reliable.toLocaleString()+' reliable ('+g.supply.toLocaleString()+' total)';
row.appendChild(role);row.appendChild(nums);card.appendChild(row);
});
}
var insight=document.createElement('div');insight.style.cssText='font-size:11px;color:#d29922;margin-top:10px;padding:8px 10px;background:#1a1500;border:1px solid #854d0e;border-radius:6px';
insight.textContent='Live from City of Chicago Open Data. Click "Verify source" to see the raw permit database. Each dot is a real permitted project — hover for details. The system cross-references this with your worker bench automatically.';
card.appendChild(insight);
el.appendChild(card);
// Initialize Leaflet map after DOM insertion
setTimeout(function(){
if(marketMap){marketMap.remove();marketMap=null}
marketMap=L.map('permit-map',{zoomControl:true,attributionControl:false}).setView([41.88,-87.7],11);
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',{maxZoom:18}).addTo(marketMap);
// Plot permits as circles sized by cost
d.major_permits.forEach(function(p){
if(!p.lat||!p.lng)return;
var cost=p.cost||0;
var radius=cost>=1e9?20:cost>=1e8?14:cost>=1e7?10:6;
var color=cost>=1e9?'#f85149':cost>=1e8?'#d29922':cost>=1e7?'#58a6ff':'#3fb950';
var costLabel=cost>=1e9?'$'+(cost/1e9).toFixed(1)+'B':cost>=1e6?'$'+(cost/1e6).toFixed(0)+'M':'$'+(cost/1e3).toFixed(0)+'K';
var circle=L.circleMarker([parseFloat(p.lat),parseFloat(p.lng)],{
radius:radius,fillColor:color,color:color,weight:1,opacity:0.8,fillOpacity:0.5
}).addTo(marketMap);
circle.bindPopup('<div style="font-size:12px;max-width:250px"><strong>'+costLabel+'</strong><br>'+
(p.description||'Construction').substring(0,120)+'<br><span style="color:#888">'+p.address+' · '+p.date+'</span></div>');
});
},100);
}).catch(function(e){
var el=document.getElementById('market');
el.textContent='Market data unavailable: '+e.message;
});
}
// ─── Learning Loop ───
// Real recruiter actions feed the Phase 19 feedback chain directly:
// Call/SMS → /log → /vectors/playbook_memory/seed (positive endorsement)
// No-show → /log_failure → /vectors/playbook_memory/mark_failed (penalty)
// Every click trains the system; the next search boosts/dampens accordingly.
function logAction(workerData, kind, btnEl){
if(!workerData)return;
var role=workerData.role||'Worker';
var city=(workerData.loc||'').split(',')[0].trim();
var state=(workerData.loc||'').split(',').pop().trim();
if(!city||!state){flashBtn(btnEl,'no geo');return;}
var op='fill: '+role+' x1 in '+city+', '+state;
if(kind==='failure'){
fetch(A+'/log_failure',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify({operation:op,failed_names:[workerData.nm],reason:'marked no-show via UI'})
}).then(function(r){return r.json()}).then(function(d){
flashBtn(btnEl, d&&d.marked?'Flagged':'Ghost');
loadLearning();
}).catch(function(){flashBtn(btnEl,'err')});
} else {
fetch(A+'/log',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify({operation:op,approach:kind+' from UI',
result:'1/1 filled → '+workerData.nm,
context:'client=ui query='+(lastQuery||'(direct)').slice(0,40)})
}).then(function(r){return r.json()}).then(function(d){
flashBtn(btnEl, d&&d.seeded?'Logged':'Ghost');
loadLearning();
}).catch(function(){flashBtn(btnEl,'err')});
}
}
function flashBtn(btn,label){
if(!btn)return;
var old=btn.textContent;btn.textContent=label;btn.disabled=true;
setTimeout(function(){btn.textContent=old;btn.disabled=false},1400);
}
// Back-compat shim — any legacy caller still pointing at logSelection.
function logSelection(workerData){ logAction(workerData, 'call', null); }
function loadLearning(){
api('/intelligence/activity',{}).then(function(d){
var el=document.getElementById('learning');
el.textContent='';
var total=d.total_operations||0;
if(total===0&&(!d.playbooks||!d.playbooks.length))return; // nothing to show yet
var card=document.createElement('div');card.className='insight info';
var lb=document.createElement('div');lb.className='label';lb.textContent='SYSTEM LEARNING';
var hl=document.createElement('div');hl.className='headline';hl.textContent='The System Gets Smarter With Every Use';
var sub=document.createElement('div');sub.className='sub';
sub.textContent='Every search, every placement, every simulation teaches the system what works. '+total+' operations logged so far.';
card.appendChild(lb);card.appendChild(hl);card.appendChild(sub);
// Stats row
var stats=document.createElement('div');stats.style.cssText='display:flex;gap:16px;margin-bottom:12px';
addLearnStat(stats,d.fill_count||0,'Contract Fills','#3fb950');
addLearnStat(stats,d.search_count||0,'Searches','#58a6ff');
addLearnStat(stats,(d.learned_patterns||[]).length,'Patterns','#bc8cff');
card.appendChild(stats);
// Learned patterns
if(d.learned_patterns&&d.learned_patterns.length){
var ph=document.createElement('div');ph.style.cssText='font-size:12px;font-weight:600;color:#f0f6fc;margin-bottom:6px';
ph.textContent='Learned Search Patterns';card.appendChild(ph);
d.learned_patterns.slice(0,5).forEach(function(p){
var row=document.createElement('div');row.style.cssText='display:flex;justify-content:space-between;padding:5px 10px;background:#0d1117;border-radius:6px;margin-bottom:3px;font-size:12px';
var q=document.createElement('span');q.style.color='#c9d1d9';q.textContent='"'+p.query+'"';
var c=document.createElement('span');c.style.cssText='color:#58a6ff;font-weight:600';c.textContent=p.times+'x';
row.appendChild(q);row.appendChild(c);card.appendChild(row);
});
}
// Recent activity feed
if(d.playbooks&&d.playbooks.length){
var ah=document.createElement('div');ah.style.cssText='font-size:12px;font-weight:600;color:#f0f6fc;margin:10px 0 6px';
ah.textContent='Recent Activity';card.appendChild(ah);
d.playbooks.slice(0,5).forEach(function(p){
var row=document.createElement('div');row.style.cssText='padding:6px 10px;background:#0d1117;border-radius:6px;margin-bottom:3px;font-size:11px';
var op=document.createElement('div');op.style.color='#f0f6fc';op.textContent=p.operation||'';
var det=document.createElement('div');det.style.cssText='color:#484f58;margin-top:2px';
det.textContent=(p.result||'')+(p.context?' · '+p.context:'');
var ts=document.createElement('div');ts.style.cssText='color:#2d333b;font-size:10px;margin-top:2px';
ts.textContent=p.timestamp?new Date(p.timestamp).toLocaleString():'';
row.appendChild(op);row.appendChild(det);row.appendChild(ts);card.appendChild(row);
});
}
// Explainer
var ex=document.createElement('div');ex.style.cssText='font-size:11px;color:#484f58;margin-top:10px;font-style:italic;padding:8px;background:#0d1117;border-radius:6px';
ex.textContent='Every time you search and select a worker, the system records what worked. Over time, it learns which workers are best for which situations — turning your decisions into institutional knowledge that never leaves when a staffer does.';
card.appendChild(ex);
el.appendChild(card);
}).catch(function(){});
}
function addLearnStat(parent,n,label,color){
var d=document.createElement('div');d.style.cssText='text-align:center;flex:1';
var num=document.createElement('div');num.style.cssText='font-size:24px;font-weight:800;color:'+color;num.textContent=n;
var lb=document.createElement('div');lb.style.cssText='font-size:10px;color:#484f58';lb.textContent=label;
d.appendChild(num);d.appendChild(lb);parent.appendChild(d);
}
</script></body></html>