---
format: typebulb/v1
name: Messiness Index
---

**code.tsx**

```tsx
import React, { useState } from "react";
import { createRoot } from "react-dom/client";

interface JobAnalysis {
  job: string;
  scores: {
    coordination: number;
    knowledge: number;
    exceptions: number;
    feedback: number;
    environment: number;
    adversarial: number;
  };
  notes: string;
}

interface Insight {
  jobs: JobAnalysis[];
}

const DIMENSIONS = [
  { key: "coordination", label: "Coord", full: "Coordination", desc: "Complexity involving people, synchronization, time pressure, and relationship depth." },
  { key: "knowledge", label: "Know", full: "Knowledge", desc: "Breadth and depth of domains touched and expertise required." },
  { key: "exceptions", label: "Except", full: "Exceptions", desc: "Frequency, cost, and novelty of unpredictable events or errors." },
  { key: "feedback", label: "Feed", full: "Feedback", desc: "Measurability, speed, and stakeholder agreement on success." },
  { key: "environment", label: "Env", full: "Environment", desc: "Physical variability, accessibility constraints, and required manual precision." },
  { key: "adversarial", label: "Adver", full: "Adversarial", desc: "Degree of active opposition, competitive stakes, and player adaptiveness." },
] as const;

type DimKey = typeof DIMENSIONS[number]["key"];

const SCORE_LABELS: Record<number, string> = {
  0: "N/A",
  1: "V.Low",
  2: "Low",
  3: "Medium",
  4: "High",
  5: "V.High",
};

function scoreColor(score: number): string {
  if (score === 0) return "#333";
  const colors = ["", "#2d5a27", "#4a7c3f", "#c9a227", "#c46210", "#a82a2a"];
  return colors[score] || "#333";
}

function totalMessiness(scores: JobAnalysis["scores"]): number {
  return Object.values(scores).reduce((sum, v) => sum + (v || 0), 0);
}

interface TooltipContent {
  title: string;
  body: React.ReactNode;
  color: string;
}

interface TooltipState {
  visible: boolean;
  x: number;
  y: number;
  content: TooltipContent | null;
}

function Popup({ state, onClose }: { state: TooltipState; onClose: () => void }) {
  if (!state.visible || !state.content) return null;
  const { title, body, color } = state.content;

  return (
    <div 
      className="popup-container" 
      style={{ left: state.x, top: state.y, borderColor: color } as any}
    >
      <div className="popup-header">
        <span className="popup-dot" style={{ backgroundColor: color }} />
        <span className="popup-title">{title}</span>
        <button className="popup-close" onClick={onClose}>×</button>
      </div>
      <div className="popup-body">{body}</div>
    </div>
  );
}

function App() {
  const [insight, setInsight] = useState<Insight | null>(() => {
    try { return tb.insight<Insight>(); } catch { return null; }
  });
  const [isGenerating, setIsGenerating] = useState(false);
  const [tooltip, setTooltip] = useState<TooltipState>({ visible: false, x: 0, y: 0, content: null });
  const [sortBy, setSortBy] = useState<DimKey | "total" | "name">("total");
  const [sortAsc, setSortAsc] = useState(false);
  const [expanded, setExpanded] = useState<Set<string>>(new Set());

  const toggleExpand = (job: string) => {
    setExpanded(prev => {
      const next = new Set(prev);
      if (next.has(job)) next.delete(job);
      else next.add(job);
      return next;
    });
  };

  const handleAnalyze = async () => {
    setIsGenerating(true);
    try {
      const result = await tb.infer<Insight>();
      if (result) {
        setInsight(result);
        setTooltip(prev => ({ ...prev, visible: false }));
      }
    } finally {
      setIsGenerating(false);
    }
  };

  const triggerPopup = (e: React.MouseEvent, content: TooltipContent) => {
    e.stopPropagation();
    const popupWidth = 320;
    const popupHeight = 240;
    const padding = 15;
    const edgeMargin = 10;

    const vw = window.innerWidth;
    const vh = window.innerHeight;

    let x = e.clientX + padding;
    let y = e.clientY + padding;

    if (x + popupWidth > vw - edgeMargin) x = e.clientX - popupWidth - padding;
    if (y + popupHeight > vh - edgeMargin) y = e.clientY - popupHeight - padding;

    x = Math.max(edgeMargin, Math.min(x, vw - popupWidth - edgeMargin));
    y = Math.max(edgeMargin, Math.min(y, vh - popupHeight - edgeMargin));

    setTooltip({ visible: true, x, y, content });
  };

  const sortedJobs = insight?.jobs.slice().sort((a, b) => {
    let cmp = 0;
    if (sortBy === "name") {
      cmp = a.job.localeCompare(b.job);
    } else if (sortBy === "total") {
      cmp = totalMessiness(b.scores) - totalMessiness(a.scores);
    } else {
      cmp = (b.scores[sortBy] || 0) - (a.scores[sortBy] || 0);
    }
    return sortAsc ? -cmp : cmp;
  });

  const handleSort = (key: DimKey | "total" | "name") => {
    if (sortBy === key) {
      setSortAsc(!sortAsc);
    } else {
      setSortBy(key);
      setSortAsc(false);
    }
  };

  return (
    <div className="app" onClick={() => setTooltip(prev => ({ ...prev, visible: false }))}>
      <Popup state={tooltip} onClose={() => setTooltip(prev => ({ ...prev, visible: false }))} />
      <header>
        <h1>How Automatable Is Your Job?</h1>
        <p className="brand">The Messiness Index</p>
        <p className="tagline">Higher messiness = harder to automate</p>
        <button className={`analyze-btn ${isGenerating ? "loading" : ""}`} onClick={handleAnalyze}>
          {isGenerating ? "Analyzing..." : "Analyze Jobs"}
        </button>
      </header>

      {insight && (
        <>
          <div className="mobile-sort">
            <label>Sort by</label>
            <select
              value={sortBy}
              onChange={e => {
                setSortBy(e.target.value as any);
                setSortAsc(false);
              }}
            >
              <option value="total">Total</option>
              <option value="name">Name</option>
              {DIMENSIONS.map(d => (
                <option key={d.key} value={d.key}>{d.full}</option>
              ))}
            </select>
            <button className="sort-dir-btn" onClick={() => setSortAsc(!sortAsc)}>
              {sortAsc ? "↑" : "↓"}
            </button>
          </div>

          <div className="card-list">
            {sortedJobs?.map(job => {
              const total = totalMessiness(job.scores);
              const isOpen = expanded.has(job.job);
              return (
                <div key={job.job} className={`card ${isOpen ? "open" : ""}`}>
                  <button className="card-header" onClick={() => toggleExpand(job.job)}>
                    <span className="card-job">{job.job}</span>
                    <span className="card-right">
                      <span className="card-total">{total}</span>
                      <span className={`card-chevron ${isOpen ? "open" : ""}`}>&#9662;</span>
                    </span>
                  </button>
                  {isOpen && (
                    <div className="card-body">
                      <div className="card-scores">
                        {DIMENSIONS.map(d => {
                          const score = job.scores[d.key] ?? 0;
                          return (
                            <div key={d.key} className="card-score-row">
                              <span className="card-dim-label">{d.full}</span>
                              <span className="card-score-badge" style={{ background: scoreColor(score) }}>
                                {SCORE_LABELS[score]}
                              </span>
                            </div>
                          );
                        })}
                      </div>
                      {job.notes && <p className="card-notes">{job.notes}</p>}
                    </div>
                  )}
                </div>
              );
            })}
          </div>

          <div className="table-wrap">
            <table className="matrix">
              <thead>
                <tr>
                  <th className={`sortable ${sortBy === "name" ? "active" : ""}`} onClick={() => handleSort("name")}>
                    <div className="header-content">
                      <span className="header-spacer" />
                      <span className="dim-label">Job</span>
                      <div className="header-icons">
                        <span className="dim-info-spacer" />
                        <span className="sort-arrow-wrap">{sortBy === "name" && (sortAsc ? "↑" : "↓")}</span>
                      </div>
                    </div>
                  </th>
                  {DIMENSIONS.map(d => (
                    <th
                      key={d.key}
                      className={`sortable dim-header ${sortBy === d.key ? "active" : ""}`}
                      onClick={() => handleSort(d.key)}
                    >
                      <div className="header-content">
                        <span className="header-spacer" />
                        <span className="dim-label">{d.full}</span>
                        <div className="header-icons">
                          <button 
                            className="dim-info-trigger"
                            onClick={(e) => triggerPopup(e, {
                              title: d.full,
                              body: <p>{d.desc}</p>,
                              color: "var(--accent)"
                            })}
                          >?</button>
                          <span className="sort-arrow-wrap">{sortBy === d.key && (sortAsc ? "↑" : "↓")}</span>
                        </div>
                      </div>
                    </th>
                  ))}
                  <th
                    className={`sortable ${sortBy === "total" ? "active" : ""}`}
                    onClick={() => handleSort("total")}
                  >
                    <div className="header-content">
                      <span className="header-spacer" />
                      <span className="dim-label">Total</span>
                      <div className="header-icons">
                        <span className="dim-info-spacer" />
                        <span className="sort-arrow-wrap">{sortBy === "total" && (sortAsc ? "↑" : "↓")}</span>
                      </div>
                    </div>
                  </th>
                </tr>
              </thead>
              <tbody>
                {sortedJobs?.map(job => (
                  <tr key={job.job}>
                    <td 
                      className="job-name clickable" 
                      onClick={(e) => triggerPopup(e, {
                        title: job.job,
                        body: (
                          <div className="job-popup-content">
                            <p className="popup-notes">{job.notes}</p>
                            <div className="radar-wrap">
                              <RadarChart scores={job.scores} />
                            </div>
                          </div>
                        ),
                        color: "var(--accent)"
                      })}
                    >
                      {job.job}
                    </td>
                    {DIMENSIONS.map(d => {
                      const score = job.scores[d.key] ?? 0;
                      return (
                        <td key={d.key} className="score-cell" style={{ background: scoreColor(score) }}>
                          {SCORE_LABELS[score]}
                        </td>
                      );
                    })}
                    <td className="total-cell">{totalMessiness(job.scores)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </>
      )}

      {!insight && (
        <div className="empty">
          <p>Add any jobs to the Data tab, then click "Analyze Jobs".</p>
          <p className="hint">We'll score each one across 6 dimensions of task complexity.</p>
        </div>
      )}
    </div>
  );
}

function RadarChart({ scores }: { scores: JobAnalysis["scores"] }) {
  const size = 200;
  const cx = size / 2;
  const cy = size / 2;
  const r = 70;
  const dims = DIMENSIONS.filter(d => scores[d.key] > 0);
  if (dims.length < 3) return <div className="radar-empty">Not enough dimensions for radar</div>;

  const points = dims.map((d, i) => {
    const angle = (Math.PI * 2 * i) / dims.length - Math.PI / 2;
    const val = scores[d.key] / 5;
    return {
      x: cx + Math.cos(angle) * r * val,
      y: cy + Math.sin(angle) * r * val,
      lx: cx + Math.cos(angle) * (r + 20),
      ly: cy + Math.sin(angle) * (r + 20),
      label: d.label,
    };
  });

  const pathD = points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ") + " Z";
  const gridLevels = [0.2, 0.4, 0.6, 0.8, 1];

  return (
    <svg width={size} height={size} className="radar">
      {gridLevels.map(level => {
        const gridPath = dims.map((_, i) => {
          const angle = (Math.PI * 2 * i) / dims.length - Math.PI / 2;
          const x = cx + Math.cos(angle) * r * level;
          const y = cy + Math.sin(angle) * r * level;
          return `${i === 0 ? "M" : "L"} ${x} ${y}`;
        }).join(" ") + " Z";
        return <path key={level} d={gridPath} className="radar-grid" />;
      })}
      {dims.map((_, i) => {
        const angle = (Math.PI * 2 * i) / dims.length - Math.PI / 2;
        return (
          <line
            key={i}
            x1={cx}
            y1={cy}
            x2={cx + Math.cos(angle) * r}
            y2={cy + Math.sin(angle) * r}
            className="radar-axis"
          />
        );
      })}
      <path d={pathD} className="radar-area" />
      {points.map((p, i) => (
        <text key={i} x={p.lx} y={p.ly} className="radar-label" textAnchor="middle" dominantBaseline="middle">
          {p.label}
        </text>
      ))}
    </svg>
  );
}

createRoot(document.getElementById("root")!).render(<App />);
```
**styles.css**

```css
:root {
  --bg: #0d1117;
  --panel: #161b22;
  --border: #30363d;
  --text: #c9d1d9;
  --dim: #8b949e;
  --accent: #58a6ff;
  --shadow: rgba(0, 0, 0, 0.4);
}

html[data-theme="light"] {
  --bg: #f6f8fa;
  --panel: #ffffff;
  --border: #d0d7de;
  --text: #24292f;
  --dim: #57606a;
  --accent: #0969da;
  --shadow: rgba(0, 0, 0, 0.1);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  font: 13px/1.5 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  padding: 16px;
}

.app { 
  max-width: 900px; 
  margin: 0 auto; 
  padding-bottom: 16px; 
}

header { text-align: center; margin-bottom: 24px; }
h1 { font-size: 32px; font-weight: 600; margin-bottom: 8px; }
.brand { font-size: 24px; color: var(--accent); font-weight: 500; margin-bottom: 8px; }
.tagline { color: var(--dim); font-size: 18px; margin-bottom: 20px; }

.analyze-btn {
  background: var(--accent);
  color: #fff;
  border: none;
  padding: 10px 24px;
  border-radius: 6px;
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  transition: opacity 0.2s;
}
.analyze-btn:hover { opacity: 0.9; }
.analyze-btn.loading { opacity: 0.6; cursor: wait; }

.summary {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px 16px;
  margin-bottom: 16px;
  font-size: 14px;
  line-height: 1.6;
}

.table-wrap { overflow-x: auto; margin-bottom: 16px; }

.matrix {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  font-size: 12px;
}

.matrix th, .matrix td {
  padding: 6px 8px;
  text-align: center;
  border-bottom: 1px solid var(--border);
}

.matrix th {
  background: var(--bg);
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0;
}

.header-content {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 8px 4px;
}

.header-spacer, .header-icons {
  display: flex;
  align-items: center;
}

.header-icons {
  gap: 2px;
  justify-content: flex-end;
}

.matrix th.sortable { cursor: pointer; user-select: none; }
.matrix th.sortable:hover { color: var(--accent); }
.matrix th.active { color: var(--accent); }

.dim-header { position: relative; }
.dim-label { cursor: pointer; flex: 1; text-align: center; white-space: nowrap; }
.dim-info-trigger {
  background: var(--border);
  color: var(--dim);
  border: none;
  border-radius: 50%;
  width: 14px;
  height: 14px;
  font-size: 10px;
  line-height: 14px;
  cursor: pointer;
  display: inline-block;
  vertical-align: middle;
  flex-shrink: 0;
}
.dim-info-trigger:hover { background: var(--accent); color: white; }

.dim-info-spacer {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.sort-arrow-wrap {
  width: 10px;
  text-align: center;
  font-size: 11px;
  color: var(--accent);
  flex-shrink: 0;
  font-family: monospace;
}

.matrix tbody tr:hover { background: rgba(88, 166, 255, 0.1); }

.job-name { text-align: left; font-weight: 500; white-space: nowrap; }
.job-name.clickable { cursor: pointer; color: var(--accent); text-decoration: underline; text-decoration-color: transparent; transition: text-decoration-color 0.2s; }
.job-name.clickable:hover { text-decoration-color: var(--accent); }

.score-cell { color: #fff; font-weight: 500; }
.total-cell { font-weight: 600; background: var(--bg); }

/* Popup Styles */
.popup-container {
  position: fixed;
  z-index: 1000;
  background: var(--panel);
  border: 2px solid;
  border-radius: 12px;
  padding: 16px;
  width: 320px;
  box-shadow: 0 10px 25px -5px var(--shadow);
  animation: popupFade 0.15s ease-out;
}

@keyframes popupFade {
  from { opacity: 0; transform: translateY(5px); }
  to { opacity: 1; transform: translateY(0); }
}

.popup-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 8px;
}

.popup-dot { width: 8px; height: 8px; border-radius: 50%; }
.popup-title { font-weight: 700; font-size: 15px; flex: 1; }
.popup-close { background: none; border: none; color: var(--dim); font-size: 20px; cursor: pointer; line-height: 1; }
.popup-close:hover { color: var(--text); }

.popup-body { font-size: 13px; line-height: 1.4; }
.popup-notes { color: var(--dim); font-style: italic; margin-bottom: 12px; }

.job-popup-content { display: flex; flex-direction: column; align-items: center; }

.radar-wrap { display: flex; justify-content: center; }
.radar-empty { color: var(--dim); font-style: italic; }

.radar .radar-grid { fill: none; stroke: var(--border); stroke-width: 1; }
.radar .radar-axis { stroke: var(--border); stroke-width: 1; }
.radar .radar-area { fill: rgba(88, 166, 255, 0.3); stroke: var(--accent); stroke-width: 2; }
.radar .radar-label { fill: var(--dim); font-size: 10px; }

.empty {
  text-align: center;
  padding: 48px;
  color: var(--dim);
}
.empty .hint { margin-top: 8px; font-size: 12px; }

/* Mobile card view */
.mobile-sort { display: none; }
.card-list { display: none; }

@media (max-width: 600px) {
  h1 { font-size: 22px; }
  .brand { font-size: 18px; }
  .tagline { font-size: 14px; }

  .table-wrap { display: none; }
  .mobile-sort { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
  .mobile-sort label { font-size: 12px; color: var(--dim); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; }
  .mobile-sort select {
    flex: 1;
    background: var(--panel);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 8px;
    font: inherit;
  }
  .sort-dir-btn {
    background: var(--panel);
    color: var(--accent);
    border: 1px solid var(--border);
    border-radius: 6px;
    width: 32px;
    height: 32px;
    font-size: 16px;
    cursor: pointer;
    font-family: monospace;
  }

  .card-list { display: flex; flex-direction: column; gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }

  .card { background: var(--panel); }
  .card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 10px 12px;
    background: none;
    border: none;
    color: var(--text);
    font: inherit;
    font-weight: 500;
    cursor: pointer;
    text-align: left;
  }
  .card-header:active { background: rgba(88, 166, 255, 0.08); }
  .card-right { display: flex; align-items: center; gap: 8px; }
  .card-total { font-weight: 700; font-size: 15px; color: var(--accent); min-width: 24px; text-align: right; }
  .card-chevron { font-size: 10px; color: var(--dim); transition: transform 0.15s; }
  .card-chevron.open { transform: rotate(180deg); }

  .card-body { padding: 0 12px 12px; }
  .card-scores { display: flex; flex-direction: column; gap: 4px; }
  .card-score-row { display: flex; align-items: center; justify-content: space-between; }
  .card-dim-label { font-size: 12px; color: var(--dim); }
  .card-score-badge {
    font-size: 11px;
    font-weight: 600;
    color: #fff;
    padding: 1px 8px;
    border-radius: 4px;
    min-width: 48px;
    text-align: center;
  }
  .card-notes { margin-top: 8px; font-size: 12px; color: var(--dim); font-style: italic; line-height: 1.4; }
}

```
**index.html**

```html
<div id="root"></div>
```
**data.txt**

```txt
Nurse
Programmer
Quant (finance)
Plumber
Litigation lawyer
ER Doctor
Factory assembly worker
Teacher (K-12)
CEO
Security researcher
Radiologist
Graphic designer
Therapist
Truck driver
Journalist
Real estate agent
Paralegal
Cashier
```
**infer.md**

```md
Analyze each job in the input data using the Task Messiness Framework.

## The Six Dimensions

Score each dimension from 0-5:
- **0 = N/A** - Dimension doesn't apply
- **1 = Very Low** - Negligible factor
- **2 = Low** - Minor factor
- **3 = Medium** - Meaningful factor
- **4 = High** - Major factor
- **5 = Very High** - Dominant factor

### Dimensions:

1. **Coordination** (people × synchronization × time pressure × relationship depth)
   - How many people involved? How tightly synchronized? Real-time pressure? Deep relationships needed?

2. **Knowledge** (domains × depth)
   - How many domains? How deep in each?

3. **Exceptions** (frequency × cost × novelty)
   - How often do things go wrong? How costly? How unprecedented?

4. **Feedback** (measurability × speed × agreement)
   - How clear is success? How fast do you know? Do stakeholders agree?

5. **Environment** (variability × accessibility × precision)
   - Physical space unpredictability? Access constraints? Dexterity required?
   - Score 0 for pure knowledge work with no physical component.

6. **Adversarial** (active opposition × stakes × adaptiveness)
   - Is someone actively working against you? High stakes? Do they adapt?
   - Score 0 if no adversarial dynamics.

## Output Format

Return a JSON object with:
- `jobs`: Array of job analyses, each with `job`, `scores` (object with all 6 dimension keys), and `notes` (1-2 sentence rationale)

```
**insight.json**

```json
{
  "jobs": [
    {
      "job": "Nurse",
      "scores": { "coordination": 5, "knowledge": 4, "exceptions": 5, "feedback": 4, "environment": 4, "adversarial": 1 },
      "notes": "Extreme coordination with doctors, patients, families. Every patient is different. Physical care on variable human bodies. Patients may resist but aren't adversarial."
    },
    {
      "job": "Programmer",
      "scores": { "coordination": 4, "knowledge": 3, "exceptions": 4, "feedback": 3, "environment": 0, "adversarial": 1 },
      "notes": "Works with PMs, designers, other devs. Multiple domains at moderate depth. Bugs and edge cases are frequent. Feedback is mixed (fast for correctness, slow for quality)."
    },
    {
      "job": "Quant (finance)",
      "scores": { "coordination": 3, "knowledge": 4, "exceptions": 4, "feedback": 3, "environment": 0, "adversarial": 4 },
      "notes": "Deep multi-domain expertise. Markets are adversarial - others exploit your edge. P&L is measurable but attribution (skill vs luck) is contested."
    },
    {
      "job": "Plumber",
      "scores": { "coordination": 2, "knowledge": 3, "exceptions": 4, "feedback": 2, "environment": 4, "adversarial": 0 },
      "notes": "Often solo. Every building is different with hidden conditions. High environmental variability - crawl spaces, behind walls. No adversarial dynamics."
    },
    {
      "job": "Litigation lawyer",
      "scores": { "coordination": 5, "knowledge": 4, "exceptions": 4, "feedback": 2, "environment": 1, "adversarial": 5 },
      "notes": "Coordinates with courts, clients, experts. Opposing counsel is explicitly adversarial and adapts to your strategy. Outcomes take years."
    },
    {
      "job": "ER Doctor",
      "scores": { "coordination": 5, "knowledge": 5, "exceptions": 5, "feedback": 3, "environment": 4, "adversarial": 1 },
      "notes": "Extreme time pressure, coordination with entire hospital. Deep expertise across emergencies. Physical intervention on critical patients. Life-or-death stakes."
    },
    {
      "job": "Factory assembly worker",
      "scores": { "coordination": 2, "knowledge": 2, "exceptions": 2, "feedback": 1, "environment": 2, "adversarial": 0 },
      "notes": "Structured, repetitive tasks. Clear success criteria. Controlled environment. Already heavily automated."
    },
    {
      "job": "Teacher (K-12)",
      "scores": { "coordination": 4, "knowledge": 3, "exceptions": 4, "feedback": 2, "environment": 3, "adversarial": 2 },
      "notes": "30 unique students, parents, administrators. Behavioral exceptions are constant. Outcomes take years to measure. Students may actively resist learning."
    },
    {
      "job": "CEO",
      "scores": { "coordination": 5, "knowledge": 4, "exceptions": 4, "feedback": 2, "environment": 1, "adversarial": 4 },
      "notes": "All coordination, all the time. Competitors, activist investors, market forces are adversarial. Feedback is slow and contested by stakeholders."
    },
    {
      "job": "Security researcher",
      "scores": { "coordination": 2, "knowledge": 4, "exceptions": 4, "feedback": 3, "environment": 0, "adversarial": 5 },
      "notes": "Deep technical expertise. Attackers actively evolve to bypass your defenses. The adversarial dimension is the core challenge - the problem resists being solved."
    },
    {
      "job": "Radiologist",
      "scores": { "coordination": 2, "knowledge": 4, "exceptions": 3, "feedback": 3, "environment": 0, "adversarial": 0 },
      "notes": "Deep imaging expertise, but mostly independent reading. AI makes inroads on pattern recognition, but rare conditions, atypical presentations, and clinical context integration remain challenging."
    },
    {
      "job": "Graphic designer",
      "scores": { "coordination": 3, "knowledge": 3, "exceptions": 3, "feedback": 2, "environment": 0, "adversarial": 0 },
      "notes": "Client coordination and iteration cycles. Design judgment and brand consistency. AI generates images but client relationships, revision loops, and taste remain human."
    },
    {
      "job": "Therapist",
      "scores": { "coordination": 3, "knowledge": 4, "exceptions": 4, "feedback": 1, "environment": 0, "adversarial": 1 },
      "notes": "Deep relationship over months/years. Each patient unique. Feedback is extremely slow (therapeutic outcomes) and subjective. Patient resistance isn't adversarial but adds complexity."
    },
    {
      "job": "Truck driver",
      "scores": { "coordination": 2, "knowledge": 2, "exceptions": 3, "feedback": 2, "environment": 4, "adversarial": 0 },
      "notes": "Self-driving's target, but environment is the barrier: weather, construction, rural roads, loading docks, mechanical issues. Highway driving is easier than last-mile."
    },
    {
      "job": "Journalist",
      "scores": { "coordination": 4, "knowledge": 3, "exceptions": 3, "feedback": 2, "environment": 2, "adversarial": 3 },
      "notes": "Source relationships, editor coordination, deadline pressure. Sources may deceive, subjects may stonewall or sue. Quality is subjective; engagement metrics are gameable."
    },
    {
      "job": "Real estate agent",
      "scores": { "coordination": 4, "knowledge": 3, "exceptions": 3, "feedback": 2, "environment": 3, "adversarial": 2 },
      "notes": "Coordinates buyers, sellers, lenders, inspectors. Local market knowledge. Physical property showings. Competing agents and negotiation dynamics. Zillow hasn't killed this yet."
    },
    {
      "job": "Paralegal",
      "scores": { "coordination": 3, "knowledge": 3, "exceptions": 2, "feedback": 2, "environment": 0, "adversarial": 1 },
      "notes": "Supports attorneys with document prep and research. More routine than attorney work. AI document review is making inroads on the lower-complexity portions."
    },
    {
      "job": "Cashier",
      "scores": { "coordination": 1, "knowledge": 1, "exceptions": 2, "feedback": 1, "environment": 1, "adversarial": 0 },
      "notes": "Minimal coordination, simple knowledge. Self-checkout has largely automated this. Remaining value is handling exceptions (returns, ID checks) and human presence preference."
    }
  ]
}

```
**config.json**

```json
{
  "dependencies": {
    "react": "^19.2.0",
    "react-dom": "^19.2.0"
  },
  "description": "How automatable is your job? The Messiness Index scores jobs across 6 dimensions of task complexity. Higher messiness = harder to automate.",
  "inference": {
    "title": "Analyze Jobs",
    "dataTitle": "Jobs to Analyze",
    "submitTitle": "Run Analysis"
  }
}
```