SPB Git

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%

chore: add file headers (author, contact, copyright, description) to all source files

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
simon-pierre boucher committed 5 days ago (Aug 5, 2026) parent c7a1562

Showing 50 changed files with +457 and −0

modified apps/etl/src/airiskindex_etl/__init__.py +9 −0
@@ -1,3 +1,12 @@
1 +# File: __init__.py
2 +# Path: apps/etl/src/airiskindex_etl/__init__.py
3 +# Project: AI Risk Index — airiskindex.io
4 +# Author: Simon-Pierre Boucher
5 +# Contact: contact@spboucher.ai
6 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +#
8 +# Description: ETL package: raw source dumps -> derived artifacts -> Postgres.
9 +
1 10 """AI Risk Index ETL: raw source dumps -> derived artifacts -> Postgres.
2 11
3 12 Raw data is never edited in place (CLAUDE.md §1); every derived artifact gets a
modified apps/etl/src/airiskindex_etl/download_oews.py +9 −0
@@ -1,3 +1,12 @@
1 +# File: download_oews.py
2 +# Path: apps/etl/src/airiskindex_etl/download_oews.py
3 +# Project: AI Risk Index — airiskindex.io
4 +# Author: Simon-Pierre Boucher
5 +# Contact: contact@spboucher.ai
6 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +#
8 +# Description: Fetch BLS OEWS national wage data into data/raw/oews/.
9 +
1 10 """Fetch BLS OEWS national wage data (May 2025) into data/raw/oews/.
2 11
3 12 BLS blocks non-browser user agents — a descriptive UA with contact info works.
modified apps/etl/src/airiskindex_etl/download_onet.py +9 −0
@@ -1,3 +1,12 @@
1 +# File: download_onet.py
2 +# Path: apps/etl/src/airiskindex_etl/download_onet.py
3 +# Project: AI Risk Index — airiskindex.io
4 +# Author: Simon-Pierre Boucher
5 +# Contact: contact@spboucher.ai
6 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +#
8 +# Description: Fetch the O*NET database text dump into data/raw/onet/.
9 +
1 10 """Fetch the O*NET database text dump into data/raw/onet/ (immutable).
2 11
3 12 O*NET 30.x — CC BY 4.0, attribution required. 30.x renamed
modified apps/etl/src/airiskindex_etl/load.py +9 −0
@@ -1,3 +1,12 @@
1 +# File: load.py
2 +# Path: apps/etl/src/airiskindex_etl/load.py
3 +# Project: AI Risk Index — airiskindex.io
4 +# Author: Simon-Pierre Boucher
5 +# Contact: contact@spboucher.ai
6 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +#
8 +# Description: Load derived CSVs into Postgres (idempotent upserts).
9 +
1 10 """Load derived O*NET + OEWS CSVs into Postgres (idempotent upserts).
2 11
3 12 Occupations are keyed by O*NET-SOC code; wages join by SOC prefix
modified apps/etl/src/airiskindex_etl/transform.py +9 −0
@@ -1,3 +1,12 @@
1 +# File: transform.py
2 +# Path: apps/etl/src/airiskindex_etl/transform.py
3 +# Project: AI Risk Index — airiskindex.io
4 +# Author: Simon-Pierre Boucher
5 +# Contact: contact@spboucher.ai
6 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +#
8 +# Description: Transform raw O*NET + OEWS dumps into derived CSVs with a manifest.
9 +
1 10 """Transform raw O*NET + OEWS dumps into derived CSVs with a manifest.
2 11
3 12 Raw is never edited in place; derived payloads are gitignored, only the
modified apps/etl/tests/test_smoke.py +9 −0
@@ -1,3 +1,12 @@
1 +# File: test_smoke.py
2 +# Path: apps/etl/tests/test_smoke.py
3 +# Project: AI Risk Index — airiskindex.io
4 +# Author: Simon-Pierre Boucher
5 +# Contact: contact@spboucher.ai
6 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +#
8 +# Description: ETL smoke tests (source configuration).
9 +
1 10 from airiskindex_etl.download_onet import ONET_URL, ONET_VERSION, RAW_DIR
2 11
3 12
modified apps/web/app/api/v1/health/route.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: route.ts
2 +// Path: apps/web/app/api/v1/health/route.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Public API: health check with index version.
9 +
1 10 import { INDEX_VERSION } from "@airiskindex/scoring";
2 11
3 12 export const dynamic = "force-dynamic";
modified apps/web/app/api/v1/methodology/route.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: route.ts
2 +// Path: apps/web/app/api/v1/methodology/route.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Public API: machine-readable weights and version metadata.
9 +
1 10 import {
2 11 DIMENSIONS,
3 12 EXPOSURE_DIMENSIONS,
modified apps/web/app/api/v1/occupations/[code]/route.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: route.ts
2 +// Path: apps/web/app/api/v1/occupations/[code]/route.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Public API: full score breakdown for one occupation.
9 +
1 10 import { prisma } from "@airiskindex/db";
2 11 import { INDEX_VERSION } from "@airiskindex/scoring";
3 12 import type { NextRequest } from "next/server";
modified apps/web/app/api/v1/occupations/route.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: route.ts
2 +// Path: apps/web/app/api/v1/occupations/route.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Public API: occupation list/search (paginated).
9 +
1 10 import { prisma } from "@airiskindex/db";
2 11 import { INDEX_VERSION } from "@airiskindex/scoring";
3 12 import type { NextRequest } from "next/server";
modified apps/web/app/globals.css +11 −0
@@ -1,3 +1,14 @@
1 +/*
2 + File: globals.css
3 + Path: apps/web/app/globals.css
4 + Project: AI Risk Index — airiskindex.io
5 + Author: Simon-Pierre Boucher
6 + Contact: contact@spboucher.ai
7 + Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
8 +
9 + Description: Design tokens (validated dataviz palette roles), card idiom, hero wash, drawer animation.
10 +*/
11 +
1 12 @tailwind base;
2 13 @tailwind components;
3 14 @tailwind utilities;
modified apps/web/app/layout.tsx +9 −0
@@ -1,3 +1,12 @@
1 +// File: layout.tsx
2 +// Path: apps/web/app/layout.tsx
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Root layout: sticky header, mobile drawer menu, preview banner, footer.
9 +
1 10 import type { Metadata, Viewport } from "next";
2 11 import Link from "next/link";
3 12 import type { ReactNode } from "react";
modified apps/web/app/methodology/page.tsx +9 −0
@@ -1,3 +1,12 @@
1 +// File: page.tsx
2 +// Path: apps/web/app/methodology/page.tsx
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Human-readable methodology documentation (weights pulled live from the engine).
9 +
1 10 import Link from "next/link";
2 11 import {
3 12 DIMENSIONS,
modified apps/web/app/occupations/[code]/page.tsx +9 −0
@@ -1,3 +1,12 @@
1 +// File: page.tsx
2 +// Path: apps/web/app/occupations/[code]/page.tsx
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Occupation detail: sub-score tiles, dimension breakdown, per-task rater audit trail.
9 +
1 10 import Link from "next/link";
2 11 import { notFound } from "next/navigation";
3 12 import { prisma } from "@airiskindex/db";
modified apps/web/app/occupations/page.tsx +9 −0
@@ -1,3 +1,12 @@
1 +// File: page.tsx
2 +// Path: apps/web/app/occupations/page.tsx
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Browse page: all occupations grouped by SOC major group with score chips.
9 +
1 10 import Link from "next/link";
2 11 import { prisma } from "@airiskindex/db";
3 12 import { SOC_MAJOR_GROUPS } from "@/lib/soc-groups";
modified apps/web/app/page.tsx +9 −0
@@ -1,3 +1,12 @@
1 +// File: page.tsx
2 +// Path: apps/web/app/page.tsx
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Home page: hero, live search, ranking (most/least exposed), group averages.
9 +
1 10 import Link from "next/link";
2 11 import { prisma } from "@airiskindex/db";
3 12 import { OccupationSearch } from "@/components/occupation-search";
modified apps/web/app/privacy/page.tsx +9 −0
@@ -1,3 +1,12 @@
1 +// File: page.tsx
2 +// Path: apps/web/app/privacy/page.tsx
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Privacy Policy.
9 +
1 10 export const metadata = {
2 11 title: "Privacy Policy — AI Risk Index",
3 12 };
modified apps/web/app/terms/page.tsx +9 −0
@@ -1,3 +1,12 @@
1 +// File: page.tsx
2 +// Path: apps/web/app/terms/page.tsx
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Terms of Service.
9 +
1 10 export const metadata = {
2 11 title: "Terms of Service — AI Risk Index",
3 12 };
modified apps/web/components/mobile-menu.tsx +10 −0
@@ -1,5 +1,15 @@
1 1 "use client";
2 2
3 +// File: mobile-menu.tsx
4 +// Path: apps/web/components/mobile-menu.tsx
5 +// Project: AI Risk Index — airiskindex.io
6 +// Author: Simon-Pierre Boucher
7 +// Contact: contact@spboucher.ai
8 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
9 +//
10 +// Description: Mobile right-side drawer menu (portal, scroll lock, Escape/overlay close).
11 +
12 +
3 13 import Link from "next/link";
4 14 import { useEffect, useState } from "react";
5 15 import { createPortal } from "react-dom";
modified apps/web/components/occupation-search.tsx +10 −0
@@ -1,5 +1,15 @@
1 1 "use client";
2 2
3 +// File: occupation-search.tsx
4 +// Path: apps/web/components/occupation-search.tsx
5 +// Project: AI Risk Index — airiskindex.io
6 +// Author: Simon-Pierre Boucher
7 +// Contact: contact@spboucher.ai
8 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
9 +//
10 +// Description: Debounced live occupation search box (client component).
11 +
12 +
3 13 import Link from "next/link";
4 14 import { useEffect, useRef, useState } from "react";
5 15
modified apps/web/components/score-marks.tsx +9 −0
@@ -1,3 +1,12 @@
1 +// File: score-marks.tsx
2 +// Path: apps/web/components/score-marks.tsx
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Chart marks: score bars with CI whiskers, stat tiles, interval strips, meter.
9 +
1 10 /**
2 11 * Chart marks for 0–100 scores with confidence bounds.
3 12 * Specs per the dataviz skill: thin bars (≤24px) with a 4px rounded data-end
modified apps/web/lib/soc-groups.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: soc-groups.ts
2 +// Path: apps/web/lib/soc-groups.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: SOC 2018 major-group names and wage formatting helpers.
9 +
1 10 /** SOC 2018 major groups — first two digits of the O*NET-SOC code. */
2 11 export const SOC_MAJOR_GROUPS: Record<string, string> = {
3 12 "11": "Management",
modified apps/web/next.config.mjs +9 −0
@@ -1,3 +1,12 @@
1 +// File: next.config.mjs
2 +// Path: apps/web/next.config.mjs
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Next.js configuration: workspace package transpilation, standalone output.
9 +
1 10 /** @type {import('next').NextConfig} */
2 11 const nextConfig = {
3 12 // Workspace packages ship TypeScript sources directly.
modified apps/web/postcss.config.mjs +9 −0
@@ -1,3 +1,12 @@
1 +// File: postcss.config.mjs
2 +// Path: apps/web/postcss.config.mjs
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: PostCSS configuration (Tailwind + autoprefixer).
9 +
1 10 export default {
2 11 plugins: {
3 12 tailwindcss: {},
modified apps/web/tailwind.config.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: tailwind.config.ts
2 +// Path: apps/web/tailwind.config.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Tailwind configuration (content scan covers app/, components/, lib/, shared ui).
9 +
1 10 import type { Config } from "tailwindcss";
2 11
3 12 export default {
modified apps/worker/src/config.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: config.ts
2 +// Path: apps/worker/src/config.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Worker configuration: rater model panel, prompt version, Redis URL.
9 +
1 10 /**
2 11 * Rater model panel — comma-separated model IDs from the environment, never
3 12 * hardcoded (CLAUDE.md §6). Multi-model rating is required: single-model
modified apps/worker/src/index.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: index.ts
2 +// Path: apps/worker/src/index.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: BullMQ worker: rating batch submit/poll/ingest jobs.
9 +
1 10 import { Queue, Worker } from "bullmq";
2 11 import IORedis from "ioredis";
3 12 import { prisma } from "@airiskindex/db";
modified apps/worker/src/raters/batch.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: batch.ts
2 +// Path: apps/worker/src/raters/batch.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Anthropic Message Batches integration: submit, poll, ingest with audit trail.
9 +
1 10 import { readFileSync } from "node:fs";
2 11 import Anthropic from "@anthropic-ai/sdk";
3 12 import { prisma } from "@airiskindex/db";
modified apps/worker/src/raters/job-id.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: job-id.ts
2 +// Path: apps/worker/src/raters/job-id.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Deterministic rating job/custom IDs (idempotent batches).
9 +
1 10 import { createHash } from "node:crypto";
2 11
3 12 /**
modified apps/worker/src/raters/schema.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: schema.ts
2 +// Path: apps/worker/src/raters/schema.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Rating response schemas (zod parse + structured-output JSON schema).
9 +
1 10 import { z } from "zod";
2 11 import { DIMENSIONS } from "@airiskindex/scoring";
3 12
modified apps/worker/src/scripts/purge-demo.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: purge-demo.ts
2 +// Path: apps/worker/src/scripts/purge-demo.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Removes the demonstration dataset once real ratings exist.
9 +
1 10 import { prisma } from "@airiskindex/db";
2 11
3 12 // Removes the demonstration dataset (synthetic tasks "XX-XXXX.00-Tn", demo
modified apps/worker/src/scripts/rate.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: rate.ts
2 +// Path: apps/worker/src/scripts/rate.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: One-shot parallel rating run with per-model resume via state file.
9 +
1 10 import { prisma } from "@airiskindex/db";
2 11 import { RATER_MODELS, RATER_PROMPT_VERSION } from "../config";
3 12 import {
modified apps/worker/src/scripts/recompute.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: recompute.ts
2 +// Path: apps/worker/src/scripts/recompute.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Full index recomputation: panel bands + overrides -> new immutable score run.
9 +
1 10 import { prisma } from "@airiskindex/db";
2 11 import {
3 12 INDEX_VERSION,
modified eslint.config.mjs +9 −0
@@ -1,3 +1,12 @@
1 +// File: eslint.config.mjs
2 +// Path: eslint.config.mjs
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: ESLint flat configuration for the monorepo.
9 +
1 10 import js from "@eslint/js";
2 11 import tseslint from "typescript-eslint";
3 12
modified infra/deploy.sh +10 −0
@@ -1,4 +1,14 @@
1 1 #!/usr/bin/env bash
2 +
3 +# File: deploy.sh
4 +# Path: infra/deploy.sh
5 +# Project: AI Risk Index — airiskindex.io
6 +# Author: Simon-Pierre Boucher
7 +# Contact: contact@spboucher.ai
8 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
9 +#
10 +# Description: Deploy script for the m3u96b node.
11 +
2 12 # Deploy to m3u96b (staging/current prod) — CLAUDE.md §7. Run ON the node.
3 13 set -euo pipefail
4 14
modified infra/run-ngrok.sh +10 −0
@@ -1,3 +1,13 @@
1 1 #!/bin/sh
2 +
3 +# File: run-ngrok.sh
4 +# Path: infra/run-ngrok.sh
5 +# Project: AI Risk Index — airiskindex.io
6 +# Author: Simon-Pierre Boucher
7 +# Contact: contact@spboucher.ai
8 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
9 +#
10 +# Description: PM2 entry: ngrok tunnel to www.airiskindex.io.
11 +
2 12 # PM2 entry for the airiskindex ngrok tunnel on m3u96b (CLAUDE.md §7).
3 13 exec /opt/homebrew/bin/ngrok http 3000 --url=https://www.airiskindex.io --log=stdout
modified infra/run-web.sh +10 −0
@@ -1,4 +1,14 @@
1 1 #!/bin/sh
2 +
3 +# File: run-web.sh
4 +# Path: infra/run-web.sh
5 +# Project: AI Risk Index — airiskindex.io
6 +# Author: Simon-Pierre Boucher
7 +# Contact: contact@spboucher.ai
8 +# Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
9 +#
10 +# Description: PM2 entry: Next.js web server on port 3000.
11 +
2 12 # PM2 entry for airiskindex-web on m3u96b (CLAUDE.md §7).
3 13 cd "$(dirname "$0")/../apps/web"
4 14 exec ./node_modules/.bin/next start -p 3000
modified packages/db/prisma/schema.prisma +9 −0
@@ -1,3 +1,12 @@
1 +// File: schema.prisma
2 +// Path: packages/db/prisma/schema.prisma
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Database schema: occupations, tasks, rating audit trail, immutable score runs.
9 +
1 10 // AI Risk Index — database schema.
2 11 // Methodology integrity (CLAUDE.md §9): every published score traces to a
3 12 // ScoreRun; runs are immutable — recomputations create new runs.
modified packages/db/prisma/seed.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: seed.ts
2 +// Path: packages/db/prisma/seed.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Demo dataset seed: 10 occupations with synthetic two-model panel ratings.
9 +
1 10 import { PrismaClient } from "@prisma/client";
2 11
3 12 // Demo seed: 10 real O*NET-SOC occupations with plausible hand-authored task
modified packages/db/src/index.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: index.ts
2 +// Path: packages/db/src/index.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Prisma client singleton shared across apps.
9 +
1 10 import { PrismaClient } from "@prisma/client";
2 11
3 12 // Singleton to avoid exhausting connections under Next.js dev hot-reload.
modified packages/scoring/src/composite.test.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: composite.test.ts
2 +// Path: packages/scoring/src/composite.test.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Snapshot tests against the published methodology worked example.
9 +
1 10 import { readFileSync } from "node:fs";
2 11 import { describe, expect, it } from "vitest";
3 12 import { HIGH_EXPOSURE_THRESHOLD, scoreOccupation } from "./index";
modified packages/scoring/src/composite.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: composite.ts
2 +// Path: packages/scoring/src/composite.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Occupation-level aggregation: importance-weighted means and highly-exposed task share.
9 +
1 10 import { scoreTask } from "./task";
2 11 import type { OccupationScores, ScoreBand, TaskInput, TaskScores } from "./types";
3 12 import { INDEX_VERSION } from "./version";
modified packages/scoring/src/index.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: index.ts
2 +// Path: packages/scoring/src/index.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Public API of the pure, deterministic scoring engine.
9 +
1 10 export { HIGH_EXPOSURE_THRESHOLD, scoreOccupation } from "./composite";
2 11 export { pressure, scoreTask } from "./task";
3 12 export type {
modified packages/scoring/src/properties.test.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: properties.test.ts
2 +// Path: packages/scoring/src/properties.test.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Property-based tests (fast-check): bounds, monotonicity, determinism, invariances.
9 +
1 10 import fc from "fast-check";
2 11 import { describe, expect, it } from "vitest";
3 12 import type { RatingBand, TaskInput, TaskRatings } from "./index";
modified packages/scoring/src/task.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: task.ts
2 +// Path: packages/scoring/src/task.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Task-level scoring: rating normalization, orientation, weighted score bands.
9 +
1 10 import type { RatingBand, ScoreBand, TaskInput, TaskScores } from "./types";
2 11 import {
3 12 DIMENSIONS,
modified packages/scoring/src/types.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: types.ts
2 +// Path: packages/scoring/src/types.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Typed inputs/outputs of the scoring engine: rating bands, score bands, task/occupation scores.
9 +
1 10 import type { DimensionKey } from "./weights";
2 11
3 12 /**
modified packages/scoring/src/version.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: version.ts
2 +// Path: packages/scoring/src/version.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Index semver version constant (bump on any methodology change).
9 +
1 10 /**
2 11 * Index version (semver). Bump on any change to weights, formulas, or rater
3 12 * prompts, with a docs/methodology/CHANGELOG.md entry — METHODOLOGY.md §7.
modified packages/scoring/src/weights.ts +9 −0
@@ -1,3 +1,12 @@
1 +// File: weights.ts
2 +// Path: packages/scoring/src/weights.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Composite dimension weights and orientation — single source of truth for the methodology.
9 +
1 10 /**
2 11 * Composite dimension weights — the single source of truth (CLAUDE.md §1:
3 12 * never hardcode weights anywhere else). METHODOLOGY.md §4.
modified packages/ui/src/index.ts +9 −0
@@ -1 +1,10 @@
1 +// File: index.ts
2 +// Path: packages/ui/src/index.ts
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Public exports of the shared UI package.
9 +
1 10 export { ScoreBandPill, type ScoreBandProps } from "./score-band";
modified packages/ui/src/score-band.tsx +9 −0
@@ -1,3 +1,12 @@
1 +// File: score-band.tsx
2 +// Path: packages/ui/src/score-band.tsx
3 +// Project: AI Risk Index — airiskindex.io
4 +// Author: Simon-Pierre Boucher
5 +// Contact: contact@spboucher.ai
6 +// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.
7 +//
8 +// Description: Shared score-band pill component (score with confidence interval).
9 +
1 10 export interface ScoreBandProps {
2 11 label: string;
3 12 low: number;
4 13