From 1f56630d5daab263e91bf443cc12832f9ab68f64 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 20 Apr 2026 16:21:27 -0500 Subject: [PATCH] #3: Worker profile modal shows past playbook history MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Click any worker card → modal now includes a 'Past Playbooks' section that queries successful_playbooks_live for any row where this worker's name appears in the result field. Shows up to 8 most recent with operation, timestamp, approach, and context. When empty: 'No prior playbooks for NAME yet. First placement builds the first entry.' — makes the institutional-memory claim visible to the recruiter: the system is tracking everyone, not just the ones that sealed this session. Also added Call / SMS / No-show buttons to the modal action row (matching the card-level buttons from #1). Every worker-card path now trains the system. Closes the user-visible side of Phase 19 — patterns surface during search (Pass A), boosts fire in ranking (Phase 19 core), and now the worker's own profile shows the full history that informs those boosts. Institutional memory legibility, per J's ask. --- mcp-server/search.html | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/mcp-server/search.html b/mcp-server/search.html index 9c4bcb6..9517d28 100644 --- a/mcp-server/search.html +++ b/mcp-server/search.html @@ -619,11 +619,51 @@ function showProfile(workerData){ body.appendChild(srcBox); } + // 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'; - acts.appendChild(callBtn);acts.appendChild(smsBtn);body.appendChild(acts); + 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); }