lakehouse/mcp-server/profiler.html
root ba41ad2846 demo: profiler index — ticker associations (direct, parent, co-permit)
J's framing: "if a contractor works for Target, future Target contracts
mean money flows back to the contractor — the ticker is an associated
indicator." Now the profiler index attaches three flavors of ticker per
contractor and renders them as colored pills:

  green DIRECT    contractor IS the public issuer (Target Corp → TGT)
  amber PARENT    contractor is a subsidiary of a public parent
                    (Turner Construction → HOC.DE via Hochtief AG)
  blue  ASSOCIATED contractor co-appears on permits with a public
                    entity (TORNOW, KYLE F → TGT, 3 shared permits with
                    TARGET CORPORATION)

The associated flavor is the correlation signal J described — it pulls
the ticker for whoever the contractor has been working *with*, not
just what they are themselves. Most contractors are private; the
associated link is how the moat shows up.

Server-side:
- entity.ts new export `lookupTickerLite(name)` — cheap in-memory
  resolver that does only the SEC tickers index lookup + curated
  KNOWN_PARENT_MAP check, no per-call SEC profile or Stooq fetch.
  ~10ms per name after the index is loaded once.
- /intelligence/profiler_index now runs a third Socrata pull
  (5K permit pairs in window) to build a co-occurrence map. For each
  contractor in the result, attaches:
    .tickers.direct[]      — name matches a public issuer
    .tickers.associated[]  — top 5 co-permit partners that resolve
                              to a ticker, with partner_name +
                              co_permits count + partner_via reason

Front-end:
- mcp-server/profiler.html — new .ticker-pill styles (3 colors per
  attribution kind), pills render under the contractor name in the
  table. Hover title gives the full reason path.

Verified end-to-end on the public URL:
  search="tornow" → blue TGT pill, hint "Associated via co-permits
                    with TARGET CORPORATION (3 shared permits) —
                    TARGET CORP"
  search="target" → green TGT × 2 (TARGET CORPORATION +
                    CORPORATION TARGET name variants both resolve
                    direct to the same issuer)
  default top 200 → 15 ticker pills surface across the page including
                    JPM (via JPMORGAN CHASE BANK co-permits) and
                    parent-link tickers for the construction majors.
2026-04-28 06:01:04 -05:00

247 lines
12 KiB
HTML

<!DOCTYPE html>
<html><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Profiler Index · Staffing Co-Pilot</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
html,body{overflow-x:hidden}
body{font-family:'Inter',-apple-system,system-ui,sans-serif;background:#090c10;color:#b0b8c4;font-size:14px;line-height:1.6}
.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}
.bar nav a{color:#545d68;text-decoration:none;font-size:12px;padding:6px 14px;border-radius:6px;margin-left:4px}
.bar nav a:hover{color:#e6edf3;background:#161b22}
.content{max-width:1200px;margin:0 auto;padding:24px 20px 40px}
.controls{background:#0d1117;border:1px solid #171d27;border-radius:10px;padding:16px;margin-bottom:14px;display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.controls input,.controls select{padding:9px 12px;background:#161b22;border:1px solid #21262d;border-radius:6px;color:#e6edf3;font-size:13px;outline:none}
.controls input:focus,.controls select:focus{border-color:#388bfd}
.controls input.s{flex:1;min-width:240px}
.controls .meta{font-size:11px;color:#8b949e;margin-left:auto}
.summary{background:#0d1117;border:1px solid #171d27;border-radius:10px;padding:14px 16px;margin-bottom:14px;font-size:12px;color:#8b949e}
.summary b{color:#e6edf3;font-weight:600}
table{width:100%;border-collapse:collapse;background:#0d1117;border:1px solid #171d27;border-radius:10px;overflow:hidden}
th{font-size:10px;color:#545d68;text-transform:uppercase;letter-spacing:1.2px;font-weight:600;text-align:left;padding:12px;background:#0a0d12;border-bottom:1px solid #171d27;cursor:pointer;user-select:none}
th:hover{color:#e6edf3}
th .arrow{font-size:9px;margin-left:4px;color:#388bfd}
td{padding:11px 12px;border-bottom:1px solid #1f2631;font-size:13px}
tr:last-child td{border-bottom:none}
tr:hover td{background:#0a0d12}
td.name a{color:#58a6ff;text-decoration:none;font-weight:600}
td.name a:hover{text-decoration:underline}
td.right{text-align:right;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums}
td.role{font-size:10px;color:#8b949e}
td.role .pill{display:inline-block;padding:2px 7px;border-radius:9px;font-size:9px;font-weight:600;background:#161b22;border:1px solid #21262d;color:#8b949e;margin-right:4px;text-transform:uppercase;letter-spacing:0.5px}
.tickers{display:flex;gap:4px;flex-wrap:wrap;margin-top:3px}
.ticker-pill{display:inline-block;padding:1px 7px;border-radius:5px;font-size:10px;font-weight:700;font-family:ui-monospace,SFMono-Regular,monospace;letter-spacing:0.3px;cursor:help}
.ticker-pill.direct{background:#0d2818;border:1px solid #2ea04388;color:#3fb950}
.ticker-pill.parent{background:#1a1410;border:1px solid #d2992288;color:#d29922}
.ticker-pill.associated{background:#0d1830;border:1px solid #58a6ff66;color:#58a6ff}
.ticker-pill.exact{background:#0d2818;border:1px solid #2ea043;color:#3fb950}
.cost-band-1{color:#3fb950}
.cost-band-2{color:#d29922}
.cost-band-3{color:#f85149}
.loading{text-align:center;padding:60px;font-size:13px;color:#3d444d}
.empty{text-align:center;padding:40px;font-size:12px;color:#545d68;font-style:italic}
.foot{margin-top:14px;font-size:10px;color:#484f58;line-height:1.6}
@media(max-width:640px){.bar{padding:0 14px}.content{padding:14px}th,td{padding:8px 6px;font-size:11px}}
</style>
</head><body>
<div class="bar">
<h1>Staffing Co-Pilot · Profiler Index</h1>
<nav>
<a href="" id="back-dashboard">← Dashboard</a>
<a href="" id="back-console">Console</a>
</nav>
</div>
<div class="content">
<div class="controls">
<input class="s" id="q" type="text" placeholder="Filter by contractor name (e.g., Target, Turner)" autocomplete="off">
<select id="since">
<option value="2025-06-01">Since June 2025</option>
<option value="2024-01-01">Since 2024</option>
<option value="2020-01-01">Since 2020 (deeper history)</option>
</select>
<select id="min-cost">
<option value="500000">$500K+</option>
<option value="250000" selected>$250K+</option>
<option value="100000">$100K+</option>
<option value="50000">$50K+</option>
</select>
<span class="meta" id="meta">Loading…</span>
</div>
<div class="summary" id="summary" style="display:none"></div>
<div id="result"><div class="loading">Loading the directory from Chicago Socrata…</div></div>
<div class="foot">Aggregations sourced live from data.cityofchicago.org (Building Permits dataset ydr8-5enu). Contractor names appear when listed as contact_1 or contact_2 on a permit. Click any name to open the full profile — heat map, project index, history, 12 awaiting public-data sources.</div>
</div>
<script>
var P=location.pathname.indexOf('/lakehouse')>=0?'/lakehouse':'';
document.getElementById('back-dashboard').href = P+'/';
document.getElementById('back-console').href = P+'/console';
var sortKey='total_cost', sortDir='desc';
var lastRows=[];
function clearChildren(el){ while(el.firstChild) el.removeChild(el.firstChild); }
function fmt$(n){
if(n>=1e9) return '$'+(n/1e9).toFixed(2)+'B';
if(n>=1e6) return '$'+(n/1e6).toFixed(1)+'M';
if(n>=1e3) return '$'+(n/1e3).toFixed(0)+'K';
return '$'+Math.round(n||0).toLocaleString();
}
function costClass(n){
if(n>=1e7) return 'cost-band-3';
if(n>=1e6) return 'cost-band-2';
return 'cost-band-1';
}
function load(){
var search=document.getElementById('q').value.trim();
var since=document.getElementById('since').value;
var minCost=parseInt(document.getElementById('min-cost').value,10);
document.getElementById('meta').textContent='Loading…';
var host=document.getElementById('result'); clearChildren(host);
var loading=document.createElement('div'); loading.className='loading';
loading.textContent='Aggregating from Chicago Socrata…';
host.appendChild(loading);
fetch(P+'/intelligence/profiler_index',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({since:since,min_cost:minCost,search:search,limit:200})
}).then(function(r){return r.json()}).then(function(d){
lastRows = d.contractors||[];
document.getElementById('meta').textContent=lastRows.length+' contractors · '+(d.duration_ms||0)+'ms';
var totalCost = lastRows.reduce(function(s,r){return s+(r.total_cost||0)},0);
var totalPermits = lastRows.reduce(function(s,r){return s+(r.permits||0)},0);
var sumDiv=document.getElementById('summary');
sumDiv.style.display='block';
clearChildren(sumDiv);
var b1=document.createElement('b'); b1.textContent=lastRows.length.toLocaleString();
sumDiv.appendChild(b1);
sumDiv.appendChild(document.createTextNode(' contractors · '));
var b2=document.createElement('b'); b2.textContent=totalPermits.toLocaleString();
sumDiv.appendChild(b2);
sumDiv.appendChild(document.createTextNode(' total permits · '));
var b3=document.createElement('b'); b3.textContent=fmt$(totalCost);
sumDiv.appendChild(b3);
sumDiv.appendChild(document.createTextNode(' aggregate value · since '+(d.since||'?')+' · min permit cost '+fmt$(d.min_cost||0)));
render();
}).catch(function(e){
document.getElementById('meta').textContent='error';
var host=document.getElementById('result'); clearChildren(host);
var er=document.createElement('div'); er.className='empty'; er.style.color='#f85149';
er.textContent='Profiler index error: '+e.message;
host.appendChild(er);
});
}
function render(){
var host=document.getElementById('result');
clearChildren(host);
if(!lastRows.length){
var emp=document.createElement('div'); emp.className='empty';
emp.textContent='No contractors match the current filter.';
host.appendChild(emp);
return;
}
var rows = lastRows.slice().sort(function(a,b){
var av=a[sortKey], bv=b[sortKey];
if(typeof av==='string'){ av=(av||'').toUpperCase(); bv=(bv||'').toUpperCase(); }
if(av<bv) return sortDir==='asc'?-1:1;
if(av>bv) return sortDir==='asc'?1:-1;
return 0;
});
var t=document.createElement('table');
var thead=document.createElement('thead'); var hr=document.createElement('tr');
var cols=[
{k:'name', label:'Contractor'},
{k:'permits', label:'Permits', right:true},
{k:'total_cost', label:'Total Value', right:true},
{k:'last_filed', label:'Last Filed', right:true},
{k:'roles', label:'Listed As'},
];
cols.forEach(function(c){
var h=document.createElement('th');
h.textContent=c.label;
if(c.right) h.style.textAlign='right';
if(sortKey===c.k){
var ar=document.createElement('span'); ar.className='arrow';
ar.textContent = sortDir==='asc' ? '▲' : '▼';
h.appendChild(ar);
}
h.onclick=function(){
if(sortKey===c.k) sortDir = sortDir==='asc' ? 'desc' : 'asc';
else { sortKey=c.k; sortDir = (c.k==='name') ? 'asc' : 'desc'; }
render();
};
hr.appendChild(h);
});
thead.appendChild(hr); t.appendChild(thead);
var tb=document.createElement('tbody');
rows.forEach(function(r){
var tr=document.createElement('tr');
var ntd=document.createElement('td'); ntd.className='name';
var a=document.createElement('a');
a.href = P+'/contractor?name='+encodeURIComponent(r.name);
a.target='_blank'; a.rel='noopener';
a.textContent = r.name;
ntd.appendChild(a);
// Ticker association pills — direct (green) = the contractor is a
// public issuer; parent (amber) = subsidiary of a public parent;
// associated (blue) = co-appears on permits with a public entity.
// Shows the correlation indicator J described — when Bob's Electric
// works permits with Target, TGT renders here as associated.
var t = r.tickers || {direct:[], associated:[]};
var allTk = (t.direct||[]).concat(t.associated||[]);
if(allTk.length){
var trk = document.createElement('div'); trk.className='tickers';
allTk.forEach(function(x){
var p = document.createElement('span');
p.className = 'ticker-pill ' + (x.via||'direct');
p.textContent = x.ticker;
// Tooltip shows the full reason path
var hint = x.via === 'associated'
? 'Associated via co-permits with '+x.partner_name+' ('+(x.co_permits||0)+' shared permits)' + (x.matched_name ? ' — '+x.matched_name : '')
: x.via === 'parent'
? 'Subsidiary of '+(x.matched_name||x.ticker) + (x.exchange ? ' · '+x.exchange : '')
: 'Direct match: '+(x.matched_name||r.name);
p.title = hint;
trk.appendChild(p);
});
ntd.appendChild(trk);
}
tr.appendChild(ntd);
var ptd=document.createElement('td'); ptd.className='right';
ptd.textContent=(r.permits||0).toLocaleString();
tr.appendChild(ptd);
var ctd=document.createElement('td'); ctd.className='right '+costClass(r.total_cost||0);
ctd.textContent=fmt$(r.total_cost||0);
tr.appendChild(ctd);
var ltd=document.createElement('td'); ltd.className='right';
ltd.textContent=(r.last_filed||'').slice(0,10) || '—';
tr.appendChild(ltd);
var rtd=document.createElement('td'); rtd.className='role';
(r.roles||[]).forEach(function(role){
var pill=document.createElement('span'); pill.className='pill'; pill.textContent=role;
rtd.appendChild(pill);
});
tr.appendChild(rtd);
tb.appendChild(tr);
});
t.appendChild(tb);
host.appendChild(t);
}
var sDeb;
document.getElementById('q').addEventListener('input',function(){
clearTimeout(sDeb);
sDeb=setTimeout(load,400);
});
document.getElementById('since').addEventListener('change',load);
document.getElementById('min-cost').addEventListener('change',load);
window.addEventListener('load',load);
</script>
</body></html>