spb/airiskindex Public
The most methodologically rigorous, fully transparent AI job-exposure index.
TypeScript 88%
Python 6.1%
SQL 2.7%
CSS 1.2%
JavaScript 0.9%
Shell 0.8%
1// File: seed.ts2// Path: packages/db/prisma/seed.ts3// Project: AI Risk Index — airiskindex.io4// Author: Simon-Pierre Boucher5// Contact: contact@spboucher.ai6// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.7//8// Description: Demo dataset seed: 10 occupations with synthetic two-model panel ratings.910import { PrismaClient } from "@prisma/client";1112// Demo seed: 10 real O*NET-SOC occupations with plausible hand-authored task13// ratings from a synthetic two-model panel ("demo-panel-a/b"). This exists so14// the site has data before the real O*NET ETL + LLM rating batch runs; the web15// layout shows a "Preview — demonstration dataset" banner, and every score16// still traces to a ScoreRun whose raterModels make the provenance explicit.17// Deterministic on purpose — reseeding yields identical ratings.1819const prisma = new PrismaClient();2021const DIMS = [22 "automatability",23 "feasibility",24 "cost_ratio",25 "barriers",26 "adoption_velocity",27 "augmentation",28] as const;2930type Dim = (typeof DIMS)[number];31type Profile = Record<Dim, number>;3233interface DemoTask {34 id: string;35 statement: string;36 importance: number;37 adjust?: Partial<Profile>;38}3940interface DemoOccupation {41 code: string;42 title: string;43 description: string;44 wageCents: number; // median annual, USD cents45 profile: Profile;46 tasks: DemoTask[];47}4849const p = (50 automatability: number,51 feasibility: number,52 cost_ratio: number,53 barriers: number,54 adoption_velocity: number,55 augmentation: number,56): Profile => ({ automatability, feasibility, cost_ratio, barriers, adoption_velocity, augmentation });5758const DEMO: DemoOccupation[] = [59 {60 code: "43-9021.00",61 title: "Data Entry Keyers",62 description:63 "Operate data entry devices to enter, verify and prepare data from source documents.",64 wageCents: 3_717_000_00 / 100,65 profile: p(5, 5, 5, 1, 4, 3),66 tasks: [67 { id: "T1", statement: "Enter account or customer data from source documents within time limits.", importance: 4.6 },68 { id: "T2", statement: "Verify entered data by reviewing, correcting or re-entering it.", importance: 4.2 },69 { id: "T3", statement: "Compile, sort and check accuracy of source documents before entry.", importance: 3.8, adjust: { automatability: -1 } },70 ],71 },72 {73 code: "43-4051.00",74 title: "Customer Service Representatives",75 description:76 "Interact with customers to handle inquiries, complaints and account questions.",77 wageCents: 3_933_000_00 / 100,78 profile: p(4, 4, 4, 2, 4, 4),79 tasks: [80 { id: "T1", statement: "Respond to routine customer inquiries about products, services and accounts.", importance: 4.7 },81 { id: "T2", statement: "Resolve complaints and escalate complex or sensitive cases.", importance: 4.1, adjust: { automatability: -1, barriers: 1 } },82 { id: "T3", statement: "Keep records of customer interactions and actions taken.", importance: 3.6, adjust: { automatability: 1 } },83 ],84 },85 {86 code: "27-3091.00",87 title: "Interpreters and Translators",88 description: "Translate or interpret written and spoken material between languages.",89 wageCents: 5_768_000_00 / 100,90 profile: p(4, 4, 4, 2, 3, 4),91 tasks: [92 { id: "T1", statement: "Translate written documents while preserving meaning, tone and register.", importance: 4.6 },93 { id: "T2", statement: "Interpret spoken exchanges in real time between parties.", importance: 4.0, adjust: { barriers: 1 } },94 { id: "T3", statement: "Proofread and quality-check translated content for accuracy.", importance: 3.7, adjust: { augmentation: 1 } },95 ],96 },97 {98 code: "15-1252.00",99 title: "Software Developers",100 description: "Design, build and maintain software systems and applications.",101 wageCents: 13_047_000_00 / 100,102 profile: p(4, 4, 3, 2, 5, 5),103 tasks: [104 { id: "T1", statement: "Write, test and debug application code to specification.", importance: 4.7 },105 { id: "T2", statement: "Design system architecture and negotiate technical trade-offs with stakeholders.", importance: 4.2, adjust: { automatability: -2, barriers: 1 } },106 { id: "T3", statement: "Review code, write documentation and maintain existing services.", importance: 3.9 },107 ],108 },109 {110 code: "13-2051.00",111 title: "Financial and Investment Analysts",112 description: "Analyze financial data to guide investment and business decisions.",113 wageCents: 9_918_000_00 / 100,114 profile: p(4, 3, 3, 3, 4, 5),115 tasks: [116 { id: "T1", statement: "Gather and consolidate financial data into models and reports.", importance: 4.5, adjust: { automatability: 1 } },117 { id: "T2", statement: "Assess valuation and risk to produce investment recommendations.", importance: 4.3, adjust: { barriers: 1 } },118 { id: "T3", statement: "Present findings and defend assumptions to clients and committees.", importance: 3.8, adjust: { automatability: -2 } },119 ],120 },121 {122 code: "23-1011.00",123 title: "Lawyers",124 description: "Advise and represent clients in legal matters and transactions.",125 wageCents: 14_531_000_00 / 100,126 profile: p(3, 3, 3, 5, 3, 4),127 tasks: [128 { id: "T1", statement: "Research case law and draft contracts, briefs and legal memoranda.", importance: 4.5, adjust: { automatability: 1, augmentation: 1 } },129 { id: "T2", statement: "Advise clients on legal strategy, risk and obligations.", importance: 4.4 },130 { id: "T3", statement: "Represent clients in negotiations, hearings and court proceedings.", importance: 4.0, adjust: { automatability: -1 } },131 ],132 },133 {134 code: "25-2021.00",135 title: "Elementary School Teachers",136 description: "Teach academic and social skills to students at the elementary level.",137 wageCents: 6_355_000_00 / 100,138 profile: p(2, 2, 2, 4, 2, 4),139 tasks: [140 { id: "T1", statement: "Prepare lesson plans, materials and assessments.", importance: 4.4, adjust: { automatability: 1, augmentation: 1 } },141 { id: "T2", statement: "Instruct and manage a classroom of students in person.", importance: 4.8, adjust: { automatability: -1, barriers: 1 } },142 { id: "T3", statement: "Grade assignments and track individual student progress.", importance: 3.9, adjust: { automatability: 1 } },143 ],144 },145 {146 code: "29-1141.00",147 title: "Registered Nurses",148 description: "Provide and coordinate patient care and educate patients about health conditions.",149 wageCents: 8_607_000_00 / 100,150 profile: p(2, 2, 2, 5, 3, 3),151 tasks: [152 { id: "T1", statement: "Assess patients and administer treatments and medications.", importance: 4.8, adjust: { automatability: -1 } },153 { id: "T2", statement: "Document care and maintain accurate patient records.", importance: 4.2, adjust: { automatability: 2, augmentation: 1 } },154 { id: "T3", statement: "Educate patients and families on conditions and care plans.", importance: 4.0 },155 ],156 },157 {158 code: "53-3032.00",159 title: "Heavy and Tractor-Trailer Truck Drivers",160 description: "Drive heavy trucks to transport goods over intercity routes.",161 wageCents: 5_411_000_00 / 100,162 profile: p(2, 2, 2, 4, 2, 2),163 tasks: [164 { id: "T1", statement: "Drive long-haul routes while complying with hours-of-service rules.", importance: 4.8, adjust: { adoption_velocity: 1 } },165 { id: "T2", statement: "Inspect vehicles and secure cargo before and after trips.", importance: 4.1 },166 { id: "T3", statement: "Plan routes and log trip records and fuel purchases.", importance: 3.5, adjust: { automatability: 2, augmentation: 1 } },167 ],168 },169 {170 code: "47-2111.00",171 title: "Electricians",172 description: "Install, maintain and repair electrical wiring and systems.",173 wageCents: 6_121_000_00 / 100,174 profile: p(1, 1, 2, 4, 2, 2),175 tasks: [176 { id: "T1", statement: "Install and repair wiring, fixtures and control systems on site.", importance: 4.8 },177 { id: "T2", statement: "Diagnose faults using test equipment and building plans.", importance: 4.3, adjust: { augmentation: 1 } },178 { id: "T3", statement: "Prepare estimates, order materials and document completed work.", importance: 3.4, adjust: { automatability: 2, augmentation: 1 } },179 ],180 },181];182183const clamp = (value: number): number => Math.max(1, Math.min(5, Math.round(value)));184185async function seedDemoOccupation(occupation: DemoOccupation): Promise<void> {186 await prisma.occupation.upsert({187 where: { code: occupation.code },188 update: { title: occupation.title, description: occupation.description, medianWageCents: Math.round(occupation.wageCents) },189 create: {190 code: occupation.code,191 title: occupation.title,192 description: occupation.description,193 medianWageCents: Math.round(occupation.wageCents),194 },195 });196197 for (const [taskIndex, task] of occupation.tasks.entries()) {198 const taskId = `${occupation.code}-${task.id}`;199 await prisma.task.upsert({200 where: { id: taskId },201 update: { statement: task.statement, importance: task.importance },202 create: {203 id: taskId,204 occupationCode: occupation.code,205 statement: task.statement,206 importance: task.importance,207 },208 });209210 for (const [dimIndex, dimension] of DIMS.entries()) {211 const base = clamp(occupation.profile[dimension] + (task.adjust?.[dimension] ?? 0));212 // Deterministic panel disagreement: model B shifts by -1/0/+1 in a fixed pattern.213 const shift = ((dimIndex + taskIndex) % 3) - 1;214 const panel: Array<[string, number]> = [215 ["demo-panel-a", base],216 ["demo-panel-b", clamp(base + shift)],217 ];218 for (const [model, rating] of panel) {219 await prisma.taskRating.upsert({220 where: {221 taskId_dimension_model_promptVersion_sampleIndex: {222 taskId,223 dimension,224 model,225 promptVersion: "v1",226 sampleIndex: 0,227 },228 },229 update: { rating },230 create: {231 taskId,232 dimension,233 model,234 promptVersion: "v1",235 sampleIndex: 0,236 rating,237 rationale: "Demonstration rating (synthetic panel) — not an LLM output.",238 rawResponse: { demo: true },239 },240 });241 }242 }243 }244}245246async function main(): Promise<void> {247 for (const occupation of DEMO) {248 await seedDemoOccupation(occupation);249 }250 console.log(251 `Seeded ${DEMO.length} demo occupations (${DEMO.reduce((n, o) => n + o.tasks.length, 0)} tasks) with synthetic panel ratings.`,252 );253 console.log("Next: RATER_MODELS=demo-panel-a,demo-panel-b pnpm score:recompute");254}255256main()257 .catch((error) => {258 console.error(error);259 process.exitCode = 1;260 })261 .finally(() => prisma.$disconnect());262