// BOS Staffing Market Scanner
// Based on the open-jobs / JobScream local-first client (github.com/elliottdehn/open-jobs).
// Flow: requisition text -> /embed -> descend the cluster manifest -> keep/skip clusters ->
// live logistic regression over the downloaded pool -> ranked openings, company rollup, CSV.
// Everything after the single /embed call runs in this tab.
const API = "https://backend.dehnbostele.workers.dev";
const $ = (s) => document.querySelector(s);
const state = { vec: null, manifest: null, cent: null, cards: [], decided: new Map(), pool: [], labels: new Map(), w: null, b: 0, shown: 0, dl: { done: 0, total: 0 }, view: "jobs" };
function show(step) {
document.querySelectorAll(".step").forEach((e) => e.classList.remove("active"));
$(step).classList.add("active");
const n = Number(step.slice(2));
for (let i = 1; i <= 3; i++) {
const r = $("#r" + i);
r.className = "rn" + (i === n ? " on" : i < n ? " done" : "");
}
window.scrollTo({ top: 0, behavior: "smooth" });
}
function norm(v) { let s = 0; for (const x of v) s += x * x; s = Math.sqrt(s) || 1; return Float32Array.from(v, (x) => x / s); }
function vec(j) { const s = atob(j.v); const buf = new ArrayBuffer(s.length); const u = new Uint8Array(buf); for (let i = 0; i < s.length; i++) u[i] = s.charCodeAt(i); return new Float32Array(buf); }
function dot(a, b) { let s = 0; for (let i = 0; i < a.length; i++) s += a[i] * b[i]; return s; }
function esc(s) { return String(s ?? "").replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ }[c])); }
// Employer labels come from whatever the board exposes. Hex client keys and GUIDs carry no name,
// so those postings are labelled honestly and the recruiter clicks through.
const HEX = /^[0-9a-f]{20,}$/i, GUID = /^[0-9a-f-]{30,}$/i;
function pretty(s) { return String(s || "").replace(/[-_]+/g, " ").replace(/\b\w/g, (m) => m.toUpperCase()).trim(); }
function coName(c) {
const v = String(c || "").trim();
if (!v || HEX.test(v) || GUID.test(v)) return "";
if (v.includes(".")) return pretty(v.split(".")[0]);
return /[\s]/.test(v) || v !== v.toLowerCase() ? v : pretty(v);
}
function co(j) {
const c = String(j.company || "").trim();
if (c && !HEX.test(c) && !GUID.test(c) && !c.includes(".")) return /[\s.]/.test(c) || c !== c.toLowerCase() ? c : pretty(c);
const slug = String(j.slug || "");
if (HEX.test(slug) || GUID.test(slug)) return "Employer not listed";
if (slug.includes(".")) return pretty(slug.split(".")[0]); // workday / oraclecloud hostnames
return pretty(slug) || "Employer not listed";
}
function say(el, msg, err) { const e = $(el); e.textContent = msg; e.className = "status" + (err ? " err" : ""); }
// ---------- index ----------
async function readWithProgress(res, onPct) {
const total = Number(res.headers.get("content-length")) || 0;
if (!res.body || !total) return res.arrayBuffer();
const reader = res.body.getReader(); const chunks = []; let got = 0;
for (;;) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value); got += value.length; onPct(Math.round((100 * got) / total));
}
const out = new Uint8Array(got); let o = 0;
for (const c of chunks) { out.set(c, o); o += c.length; }
return out.buffer;
}
async function loadManifest() {
if (state.manifest) return;
say("#st1", "Loading job index, this runs once per browser…");
const [mr, cr] = await Promise.all([fetch(`${API}/data/manifest.json`), fetch(`${API}/data/centroids.bin`)]);
if (!mr.ok || !cr.ok) throw new Error(mr.status === 404 ? "The job index has not been published yet. Try again shortly." : `Could not load the job index (HTTP ${mr.status}).`);
const cbuf = await readWithProgress(cr, (p) => say("#st1", `Loading job index… ${p}%`));
const m = await mr.json();
state.manifest = m;
const u16 = new Uint16Array(cbuf), f = new Float32Array(u16.length);
for (let i = 0; i < u16.length; i++) f[i] = f16(u16[i]);
state.cent = f;
$("#corpus").textContent = `${m.jobs.toLocaleString()} open postings · ${m.leaves.toLocaleString()} clusters\n${m.recipe}`;
$("#corpus").style.whiteSpace = "pre";
}
function f16(h) { const s = (h & 0x8000) ? -1 : 1, e = (h >> 10) & 0x1f, m = h & 0x3ff; if (e === 0) return s * m * 2 ** -24; if (e === 31) return m ? NaN : s * Infinity; return s * (1 + m / 1024) * 2 ** (e - 15); }
function centroid(i) { const d = state.manifest.dims; return state.cent.subarray(i * d, (i + 1) * d); }
function nearestNodes(q, want) {
const T = state.manifest.tree, leaves = [];
for (const n of T) if (!n.children.length) leaves.push([dot(q, centroid(n.id)), n]);
leaves.sort((a, b) => b[0] - a[0]);
return leaves.slice(0, want).map(([, n]) => n);
}
function leavesUnder(n) { const T = state.manifest.tree, out = [], st = [n]; while (st.length) { const x = st.pop(); if (!x.children.length) out.push(x); else for (const c of x.children) st.push(T[c]); } return out; }
// ---------- step 1 ----------
$("#go").onclick = async () => {
const text = $("#resume").value.trim();
if (text.length < 20) { say("#st1", "Add a bit more detail before scanning.", true); return; }
$("#go").disabled = true;
try {
await loadManifest();
say("#st1", "Matching against the index…");
const r = await fetch(`${API}/embed`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ text, title: $("#title").value, location: $("#loc").value }) });
if (!r.ok) {
const e = await r.json().catch(() => ({}));
throw new Error(e.error ? `${e.error}${e.retryAfterSeconds ? `. Retry in ${e.retryAfterSeconds}s.` : ""}` : `Request failed (HTTP ${r.status}).`);
}
const { vector, recipe } = await r.json();
state.vec = norm(vector);
say("#st1", recipe !== state.manifest.recipe ? `Heads up: index recipe ${state.manifest.recipe} does not match ${recipe}.` : "");
renderCards(24); show("#s2");
} catch (e) { say("#st1", String(e.message || e), true); }
$("#go").disabled = false;
};
// ---------- step 2 ----------
function renderCards(want) {
state.cards = nearestNodes(state.vec, want);
const el = $("#cards"); el.innerHTML = "";
for (const n of state.cards) {
const sim = dot(state.vec, centroid(n.id));
const d = document.createElement("div");
d.className = "card " + (state.decided.get(n.id) || "");
d.innerHTML = `
${esc(n.label || n.medoid)}
${n.size.toLocaleString()} openings${n.distinct_titles ? ` · ${n.distinct_titles} distinct titles` : ""} · match ${sim.toFixed(2)} · spread ${n.radius.toFixed(2)}
${n.exemplars.map((e) => { const c = coName(e.company); return `${esc(e.title)} ${c ? "· " + esc(c) : ""}${e.location ? " · " + esc(e.location) : ""} `; }).join("")}
Keep Skip
`;
d.querySelector(".btn-yes").onclick = () => decide(n, "maybe", d);
d.querySelector(".btn-no").onclick = () => decide(n, "no", d);
el.appendChild(d);
}
}
$("#more").onclick = () => renderCards(state.cards.length + 24);
function decide(n, v, el) {
state.decided.set(n.id, v); el.className = "card " + v;
if (v === "maybe") for (const leaf of leavesUnder(n)) fetchGroup(leaf);
$("#next2").disabled = ![...state.decided.values()].includes("maybe");
}
const groups = new Map();
async function fetchGroup(leaf) {
if (groups.has(leaf.id)) return;
groups.set(leaf.id, null); state.dl.total++; updDl();
const gr = await fetch(`${API}/data/groups/${leaf.id}.json`);
if (!gr.ok) { groups.delete(leaf.id); state.dl.total--; updDl(); return; }
const g = await gr.json();
for (const j of g.jobs) { j.v = vec(j); j.leaf = leaf.id; j.sim = dot(state.vec, j.v); state.pool.push(j); }
groups.set(leaf.id, g); state.dl.done++; updDl();
}
function updDl() {
$("#dl").textContent = state.dl.total ? `${state.dl.done} of ${state.dl.total} clusters downloaded · ${state.pool.length.toLocaleString()} openings held locally` : "";
$("#dlbar").style.width = state.dl.total ? `${(100 * state.dl.done) / state.dl.total}%` : "0";
}
$("#next2").onclick = () => { seedNegatives(); refit(); render(true); show("#s3"); };
// ---------- step 3 ----------
function seedNegatives() {
for (const [id, v] of state.decided) if (v === "no") {
const n = state.manifest.tree[id];
for (const leaf of leavesUnder(n).slice(0, 2)) fetch(`${API}/data/groups/${leaf.id}.json`).then((r) => r.json()).then((g) => {
for (const j of g.jobs.slice(0, 5)) { j.v = vec(j); j.neg = true; j.sim = dot(state.vec, j.v); state.pool.push(j); state.labels.set(key(j), 0); }
refit(); render(false);
}).catch(() => {});
}
}
const key = (j) => `${j.ats}/${j.slug}#${j.id}`;
function refit() {
const D = state.manifest.dims, items = state.pool.filter((j) => state.labels.has(key(j)));
const pos = items.filter((j) => state.labels.get(key(j)) === 1).length, neg = items.length - pos;
if (pos === 0 || neg === 0) {
state.w = null;
say("#st3", `Ranked by requisition match. Mark at least one keep and one drop to train the model. Currently ${pos} keep / ${neg} drop.`);
return;
}
const w = Float32Array.from(state.vec); let b = 0; const lr = 0.5, l2 = 0.01;
for (let ep = 0; ep < 30; ep++) for (const j of items) {
const y = state.labels.get(key(j)), p = 1 / (1 + Math.exp(-(dot(w, j.v) + b))), g = p - y;
for (let i = 0; i < D; i++) w[i] -= lr * (g * j.v[i] + l2 * (w[i] - state.vec[i]));
b -= lr * g;
}
state.w = w; state.b = b;
say("#st3", `Model trained on ${pos} keep / ${neg} drop · ${state.pool.length.toLocaleString()} openings ranked locally`);
}
function score(j) { return state.w ? 1 / (1 + Math.exp(-(dot(state.w, j.v) + state.b))) : j.sim; }
let ranked = [], cur = 0;
function render(reset) {
ranked = state.pool.filter((j) => !j.neg).sort((a, b) => score(b) - score(a));
if (reset) state.shown = 0;
state.view === "jobs" ? renderJobs() : renderCos();
}
function renderJobs() {
const el = $("#jobs"); el.innerHTML = "";
if (!ranked.length) { el.innerHTML = `No openings loaded. Go back and keep at least one cluster.
`; return; }
const N = Math.min(ranked.length, state.shown + 40);
for (let i = 0; i < N; i++) el.appendChild(jobEl(ranked[i], i));
state.shown = N; cur = Math.min(cur, N - 1); hi();
}
function jobEl(j, i) {
const d = document.createElement("div"), l = state.labels.get(key(j)), s = score(j);
d.className = "job " + (l === 1 ? "pos" : l === 0 ? "neg" : ""); d.dataset.i = i;
d.innerHTML = `
${esc(j.title)}
${esc(co(j))}
${esc(j.jd || "(no description on file)")}
${s.toFixed(2)}
`;
d.querySelector("a").onclick = (e) => e.stopPropagation();
d.onclick = () => { cur = i; hi(); const x = d.querySelector(".jd"); x.style.display = x.style.display === "block" ? "none" : "block"; };
return d;
}
function hi() {
document.querySelectorAll(".job").forEach((e, i) => e.classList.toggle("cur", i === cur));
const e = document.querySelector(`.job[data-i="${cur}"]`); if (e) e.scrollIntoView({ block: "nearest" });
}
// Board-level rollup: one row per hiring board, which is one employer. Names come from the
// backend's company resolution when it has run for that board (opt-in, ~2 KB per board).
function rollup() {
const by = new Map();
for (const j of ranked) {
const k = `${j.ats}/${j.slug}`;
const c = by.get(k) || { name: co(j), ats: j.ats, n: 0, best: 0, locs: new Set(), url: j.url };
c.n++; c.best = Math.max(c.best, score(j)); if (j.location) c.locs.add(j.location);
by.set(k, c);
}
return [...by.values()].sort((a, b) => b.n - a.n || b.best - a.best);
}
function renderCos() {
const rows = rollup().slice(0, 150);
const el = $("#cos"); el.innerHTML = "";
if (!rows.length) { el.innerHTML = `No openings loaded yet.
`; return; }
for (const c of rows) {
const locs = [...c.locs].slice(0, 3).join(" · ") + (c.locs.size > 3 ? ` +${c.locs.size - 3} more` : "");
const d = document.createElement("div"); d.className = "comp";
d.innerHTML = `${esc(c.name)} ${esc(c.ats)}
${esc(locs) || "location not listed"}
`;
el.appendChild(d);
}
}
$("#vJobs").onclick = () => setView("jobs");
$("#vCos").onclick = () => setView("cos");
function setView(v) {
state.view = v;
$("#vJobs").classList.toggle("on", v === "jobs"); $("#vCos").classList.toggle("on", v === "cos");
$("#jobs").style.display = v === "jobs" ? "" : "none"; $("#cos").style.display = v === "cos" ? "" : "none";
$("#more3").style.display = v === "jobs" ? "" : "none";
render(false);
}
$("#more3").onclick = () => render(false);
$("#csv").onclick = () => {
const q = (s) => `"${String(s ?? "").replace(/"/g, '""').replace(/\s+/g, " ").trim()}"`;
const head = "match,title,employer,location,url,source,marked\n";
const body = ranked.map((j) => {
const l = state.labels.get(key(j));
return [score(j).toFixed(4), q(j.title), q(co(j)), q(j.location), q(j.url), q(j.ats), l === 1 ? "keep" : l === 0 ? "drop" : ""].join(",");
}).join("\n");
const blob = new Blob([head + body], { type: "text/csv;charset=utf-8" });
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = `bos-market-scan-${new Date().toISOString().slice(0, 10)}.csv`;
a.click(); URL.revokeObjectURL(a.href);
};
document.addEventListener("keydown", (ev) => {
if (!$("#s3").classList.contains("active") || state.view !== "jobs" || ev.target.tagName === "TEXTAREA" || ev.target.tagName === "INPUT") return;
const j = ranked[cur]; if (!j) return;
if (ev.key === "j" || ev.key === "J") { state.labels.set(key(j), 1); refit(); render(false); cur++; hi(); }
else if (ev.key === "k" || ev.key === "K") { state.labels.set(key(j), 0); refit(); render(false); cur++; hi(); }
else if (ev.key === " ") { ev.preventDefault(); cur++; hi(); }
else if (ev.key === "ArrowUp") { cur = Math.max(0, cur - 1); hi(); }
else if (ev.key === "ArrowDown") { cur++; hi(); }
});