Matrix-index the "who handled this" dimension so top staffers become
the training signal and juniors inherit their playbooks automatically
via the boost pipeline. Auto-discovered indicators emerge from
comparing trajectories across staffers on similar contracts — that was
always the architectural point; this wires the last piece.
ContractTerms:
- deadline, budget_total_usd, budget_per_hour_max, local_bonus_per_hour,
local_bonus_radius_mi, fill_requirement ("paramount" | "preferred")
- Attached to ScenarioSpec, propagated into T3 checkpoint + cloud
rescue prompts so cloud reasons about trade-offs (pivot within bonus
radius first; respect per-hour cap; split across cities when
fill_requirement=paramount).
Staffer:
- {id, name, tenure_months, role: senior|mid|junior|trainee}
- On ScenarioSpec; logged at scenario start; attached to KB outcome
- Recomputed StafferStats written to data/_kb/staffers.jsonl after
every run: total_runs, fill_rate, avg_turns, avg_citations,
rescue_rate, competence_score.
- Competence formula: 0.45*fill_rate + 0.20*turn_efficiency +
0.20*citation_density + 0.15*rescue_rate. Normalized to 0..1.
findNeighbors now returns weighted_score = cosine × best_staffer_competence
(floored at 0.3 so high-similarity low-competence neighbors still
surface). pathway_recommender prompt shows the top staffer's identity
so cloud knows WHOSE playbook it's synthesizing from.
Demo infrastructure:
- tests/multi-agent/gen_staffer_demo.ts: 4 personas (Maria senior,
James mid, Sam junior, Alex trainee) × 3 contracts (Nashville Welder,
Joliet Warehouse, Indianapolis Assembly). 12 scenarios total.
- scripts/run_staffer_demo.sh: runs the 12 sequentially with
LH_OVERVIEW_CLOUD=1. Post-run calls kb_staffer_report.py.
- scripts/kb_staffer_report.py: leaderboard + cross-staffer worker
overlap (names endorsed by ≥2 staffers → auto-discovered high-value
workers). Top vs bottom differential.
gen_scenarios.ts (Phase 22 generator) also now emits contract terms
on 70% of generated specs — future KB batches populate with realistic
constraint patterns instead of bare role+city+count.
Stress scenario from item A intentionally NOT the production test.
Real staffing has constraints; Nashville contract + staffer demo is
the honest test of whether the architecture produces measurable
differential between coordinator skill levels.
Demo batch launched — 12 runs × ~3min each ≈ 40min unattended. Report
emitted after batch.
121 lines
4.9 KiB
TypeScript
121 lines
4.9 KiB
TypeScript
// Phase 23 demo — 4 staffer personas × 3 contract scenarios each.
|
||
// Same contracts run against different staffers to measure competence
|
||
// differential. After the batch, findNeighbors should rank top-staffer
|
||
// playbooks above junior-staffer playbooks for similar scenarios.
|
||
//
|
||
// Output: 12 spec files under tests/multi-agent/scenarios/staffer_demo/
|
||
|
||
import { mkdir, writeFile } from "node:fs/promises";
|
||
import { join } from "node:path";
|
||
|
||
const STAFFERS = [
|
||
{ id: "S-001", name: "Maria Chen", tenure_months: 48, role: "senior" as const },
|
||
{ id: "S-002", name: "James Park", tenure_months: 14, role: "mid" as const },
|
||
{ id: "S-003", name: "Sam Torres", tenure_months: 4, role: "junior" as const },
|
||
{ id: "S-004", name: "Alex Rivera", tenure_months: 1, role: "trainee" as const },
|
||
];
|
||
|
||
// Three contract shapes — one downtown assembly, one warehouse ramp,
|
||
// one emergency recovery. Different cities to vary the sig_hash.
|
||
const CONTRACTS = [
|
||
{
|
||
tag: "nashville_downtown",
|
||
client: "Riverline Logistics — Nashville Downtown Build-Out",
|
||
city: "Nashville", state: "TN",
|
||
contract: {
|
||
deadline: "2026-05-19",
|
||
budget_total_usd: 180000,
|
||
budget_per_hour_max: 32,
|
||
local_bonus_per_hour: 4,
|
||
local_bonus_radius_mi: 75,
|
||
fill_requirement: "paramount" as const,
|
||
},
|
||
events: [
|
||
{ kind: "baseline_fill", at: "07:00", role: "Welder", count: 4 },
|
||
{ kind: "expansion", at: "08:30", role: "Packaging Operator", count: 6 },
|
||
{ kind: "baseline_fill", at: "09:00", role: "Shipping Clerk", count: 2 },
|
||
{ kind: "emergency", at: "13:00", role: "Welder", count: 2, deadline: "15:00" },
|
||
{ kind: "misplacement", at: "15:30", role: "Packaging Operator", count: 1, replaces_event: "08:30" },
|
||
],
|
||
},
|
||
{
|
||
tag: "joliet_warehouse",
|
||
client: "Midway Distribution — Joliet DC Ramp",
|
||
city: "Joliet", state: "IL",
|
||
contract: {
|
||
deadline: "2026-05-12",
|
||
budget_total_usd: 120000,
|
||
budget_per_hour_max: 28,
|
||
local_bonus_per_hour: 3,
|
||
local_bonus_radius_mi: 50,
|
||
fill_requirement: "preferred" as const,
|
||
},
|
||
events: [
|
||
{ kind: "baseline_fill", at: "07:00", role: "Warehouse Associate", count: 5 },
|
||
{ kind: "recurring", at: "10:00", role: "Forklift Operator", count: 3 },
|
||
{ kind: "expansion", at: "12:30", role: "Picker", count: 4 },
|
||
{ kind: "misplacement", at: "15:00", role: "Forklift Operator", count: 1, replaces_event: "10:00" },
|
||
],
|
||
},
|
||
{
|
||
tag: "indianapolis_assembly",
|
||
client: "Pioneer Assembly — Indianapolis Plant Expansion",
|
||
city: "Indianapolis", state: "IN",
|
||
contract: {
|
||
deadline: "2026-05-26",
|
||
budget_total_usd: 220000,
|
||
budget_per_hour_max: 30,
|
||
local_bonus_per_hour: 5,
|
||
local_bonus_radius_mi: 60,
|
||
fill_requirement: "paramount" as const,
|
||
},
|
||
events: [
|
||
{ kind: "baseline_fill", at: "07:30", role: "Assembler", count: 6 },
|
||
{ kind: "recurring", at: "09:30", role: "Quality Tech", count: 2 },
|
||
{ kind: "expansion", at: "11:00", role: "Machine Operator", count: 5 },
|
||
{ kind: "emergency", at: "14:00", role: "Machine Operator", count: 3, deadline: "16:00" },
|
||
{ kind: "misplacement", at: "16:00", role: "Assembler", count: 1, replaces_event: "07:30" },
|
||
],
|
||
},
|
||
];
|
||
|
||
async function main() {
|
||
const outDir = "tests/multi-agent/scenarios/staffer_demo";
|
||
await mkdir(outDir, { recursive: true });
|
||
const manifest: Array<{ file: string; staffer: string; contract: string; client: string }> = [];
|
||
let day = 0;
|
||
for (const staffer of STAFFERS) {
|
||
for (const ct of CONTRACTS) {
|
||
day += 1;
|
||
const date = new Date(Date.now() + day * 86400000).toISOString().split("T")[0];
|
||
const spec = {
|
||
client: ct.client,
|
||
date,
|
||
contract: ct.contract,
|
||
staffer,
|
||
events: ct.events.map(e => ({
|
||
...e,
|
||
city: ct.city,
|
||
state: ct.state,
|
||
shift_start: `${e.at} ${e.at.startsWith("0") ? "AM" : "PM"}`,
|
||
scenario_note: `Staffed by ${staffer.name} (${staffer.role}, ${staffer.tenure_months}mo). Contract deadline ${ct.contract.deadline}, fill=${ct.contract.fill_requirement}.`,
|
||
})),
|
||
};
|
||
const fname = `${staffer.id}_${ct.tag}.json`;
|
||
await writeFile(join(outDir, fname), JSON.stringify(spec, null, 2));
|
||
manifest.push({ file: fname, staffer: staffer.name, contract: ct.tag, client: ct.client });
|
||
}
|
||
}
|
||
await writeFile(
|
||
join(outDir, "manifest.json"),
|
||
JSON.stringify({ count: manifest.length, scenarios: manifest }, null, 2),
|
||
);
|
||
console.log(`✓ ${manifest.length} staffer-demo specs → ${outDir}/`);
|
||
for (const m of manifest) console.log(` ${m.file} — ${m.staffer} × ${m.contract}`);
|
||
}
|
||
|
||
main().catch(e => {
|
||
console.error("gen_staffer_demo failed:", (e as Error).message);
|
||
process.exit(1);
|
||
});
|