spb/modelmap Public License
Internal cartography of local LLMs on Apple Silicon — registered, gated, negative-first. Public atlas at modelmap.io.
Python 66.3%
JavaScript 24.5%
CSS 8.1%
Shell 0.7%
1// ============================================================================2// Project : modelmap3// File : site/server.js4// Purpose : modelmap.io platform — routes and pages (English, light theme)5// Author : Simon-Pierre Boucher6// Contact : contact@spboucher.ai7// Website : https://modelmap.io8// Created : 2026-08-129// Modified : 2026-08-1210// Platform : macOS / Apple Silicon (arm64) — Node.js (deployed on MacLustr)11// License : All rights reserved (research code)12// ============================================================================13"use strict";1415const path = require("path");16const express = require("express");17const C = require("./lib/content");18const R = require("./lib/render");19const Comments = require("./lib/comments");20const Charts = require("./lib/charts");2122// ------------------------------------------------------------ chart builders23/** Layer-profile charts for a probes atlas entry (real A/B + twin null). */24function probeMapCharts(onlyProp, mapRel) {25 const m = C.readJson(mapRel || "atlas/qwen3-0.6b-4bit/probes/v1/map.json");26 if (!m || !m.properties) return "";27 const props = onlyProp ? [onlyProp] : Object.keys(m.properties);28 return props.map((prop) => {29 const p = m.properties[prop];30 if (!p) return "";31 const sel = (rows) => rows.map((r) => r.selectivity_mean);32 const caption = p.verdict33 ? `Verdict: ${R.esc(p.verdict)}. Differential (real−twin) claims only; Level 1, ` +34 "5 seeds, shuffled-label controls inside every probe, token-balanced classes."35 : "The twin (dashed) matches the trained model — the registered validity gate " +36 "failed and this map is published as a NEGATIVE result: on these promptsets, probes " +37 "read the tokenizer + architecture prior, not learned computation. Level 1, 5 seeds, " +38 "shuffled-label controls inside every probe.";39 return Charts.layerLineSvg({40 title: `${prop} — probe selectivity by layer (trained vs random-init twin)`,41 yLabel: "selectivity",42 yMin: 0, yMax: 1,43 series: [44 { label: "trained · set A", color: Charts.S1, values: sel(p.per_layer.A) },45 { label: "trained · set B", color: Charts.S2, values: sel(p.per_layer.B) },46 { label: "random-init twin", color: Charts.REF, dash: true, ref: true,47 values: p.twin_null_per_layer_A.map((r) => r.selectivity_mean) },48 ],49 caption,50 });51 }).join("");52}53const MAP_V2 = "atlas/qwen3-0.6b-4bit/probes/v2/map.json";54const MAP_INT = "atlas/qwen3-0.6b-4bit/interventions/v1/map.json";5556/** Causal direction-erasure BAND map chart (interventions map, run #4 format). */57function interventionsMapCharts(mapRel) {58 const m = C.readJson(mapRel || MAP_INT);59 if (!m || !m.per_layer || !m.per_layer.mean) return "";60 const all = [...m.per_layer.mean, ...m.per_layer.min, ...m.per_layer.random_direction_damage];61 const yMin = Math.floor(Math.min(...all, 0) * 2) / 2 - 0.5;62 const yMax = Math.ceil(Math.max(...all) * 2) / 2 + 0.5;63 const band = m.band || {};64 return Charts.layerLineSvg({65 title: "agreement — causal direction-erasure BAND map (specific damage by layer)",66 yLabel: "specific margin damage",67 yMin, yMax,68 series: [69 { label: "mean of 6 fresh sources", color: Charts.S1, values: m.per_layer.mean },70 { label: "worst source (min)", color: Charts.S2, values: m.per_layer.min },71 { label: "random-direction damage", color: Charts.REF, dash: true, ref: true,72 values: m.per_layer.random_direction_damage },73 ],74 caption: `The published claim is the BAND (layers ${band.early_layers ? band.early_layers.join("–") : "2–15"}): ` +75 "erasing the diff-of-means agreement direction at any single early-band layer destroys most of " +76 "the grammatical margin (baseline " + (m.baseline_margin ? m.baseline_margin.toFixed(2) : "—") +77 "), replicated across six fresh direction estimates on a fresh behavioral bank (Level 2). " +78 "The late band is displayed but carries no claim — run #3's per-layer version was refused by " +79 "the publication gate as estimator-unstable. Anti-correlates with the probes/v2 decodability " +80 "ranking (survival ledger 0/2): decodability peaks ≠ causal joints.",81 });82}8384/** expH charts: warm/cold storage panels + capture-overhead grouped bars. */85function storageChart() {86 const d = C.expHData();87 let html = "";88 if (d.warm && d.cold) {89 const rnd = (rows) => rows.filter((r) => r.op === "random-batch")90 .map((r) => ({ label: r.format.replace("zarr-", "zarr‑"), value: r.gb_per_s_mean }));91 html += Charts.barPanelsSvg({92 title: "Activation-store random-batch read throughput — the ordering inverts cold",93 yLabel: "GB/s", unit: "GB/s",94 panels: [95 { title: "warm cache · M5 Max (run #1)", bars: rnd(d.warm) },96 { title: "cold cache · M3 Ultra (run #2)", bars: rnd(d.cold) },97 ],98 caption: "Run #2 falsified the registered hypothesis: raw mmap wins warm (memory speed) " +99 "but collapses cold to page-fault IO (~8–16 KiB, QD 1) while chunked zarr reads 32 MiB " +100 "blocks. The rule is IO granularity, not the container.",101 });102 }103 return html;104}105106function captureChart() {107 const d = C.expHData();108 let html = "";109 if (d.compute.length) {110 const key = (c) => `${c.backend}·${c.source}`;111 const groupsMap = new Map();112 for (const c of d.compute) {113 const ms = 1000 * c.s_per_forward.reduce((a, b) => a + b, 0) / c.s_per_forward.length;114 if (!groupsMap.has(key(c))) groupsMap.set(key(c), { backend: c.backend, source: c.source, values: {} });115 groupsMap.get(key(c)).values[c.mode] = ms;116 }117 const label = (g) => g.backend === "torch-mps" ? "torch-MPS (synthetic)" :118 g.source === "synthetic" ? "MLX (synthetic)" : "MLX (Qwen3-0.6B-4bit)";119 html += Charts.groupedBarSvg({120 title: "Capture overhead per forward pass — retention is nearly free under MLX",121 yLabel: "ms / forward", unit: "ms",122 groups: [...groupsMap.values()].map((g) => ({ label: label(g), values: g.values })),123 modes: [124 { key: "plain", label: "plain", color: Charts.S1 },125 { key: "retain", label: "retain", color: Charts.S2 },126 { key: "retain+copy+write", label: "retain+copy+write", color: Charts.S3 },127 ],128 caption: "Runs #1 and #3: per-layer retention costs 1.02× (MLX synthetic) and 1.004× " +129 "(real 4-bit checkpoint) vs 1.22× on torch-MPS; copy+write stays ≤1.5× everywhere. " +130 "3 repeats per cell; manifests embedded in the raw JSON.",131 });132 }133 return html;134}135136function expHCharts() {137 return storageChart() + captureChart();138}139140const app = express();141const PORT = process.env.PORT || 8140;142143app.set("trust proxy", true); // behind ngrok — X-Forwarded-For carries the real IP144app.use("/static", express.static(path.join(__dirname, "public"), { maxAge: "1h" }));145app.use(express.urlencoded({ extended: false, limit: "16kb" }));146147function page(res, opts) {148 res.send(R.layout({ ...opts, buildInfo: C.buildInfo() }));149}150151function metaChips(data) {152 if (!data || !Object.keys(data).length) return "";153 const fields = ["document", "author", "created", "modified", "status"];154 const chips = fields155 .filter((f) => data[f])156 .map((f) => `<span class="chip"><span class="chip-k">${f}</span>${R.esc(data[f])}</span>`)157 .join("");158 return chips ? `<div class="chips">${chips}</div>` : "";159}160161// ---------------------------------------------------------------- home162app.get("/", (req, res) => {163 const s = C.stats();164 const log = C.parseLogEntries().slice(-3).reverse();165 const phases = [166 ["Phase 1 — Ultra-deep literature research (§4.1–4.10)", s.notes > 0 ? "in progress" : "pending", s.notes > 0 ? `${s.notes} theme notes · ${s.sources} sources` : "ten mandatory areas, primary sources first"],167 ["Phase 2 — State-of-the-art map", C.exists("research/state_of_the_art.md") ? "done" : "pending", "technique taxonomy with epistemic status"],168 ["Phase 3 — Research gaps", s.gaps ? "done" : "pending", s.gaps ? `${s.gaps} falsifiable candidate directions` : "≥20 substantially different candidate directions"],169 ["Phase 4 — Candidate ranking", C.exists("research/candidate_ranking.md") ? "done" : "pending", "10-axis scoring, 3–5 prototype candidates"],170 ["Phases 5–6 — Framework & micro-experiments A–H", s.experimentsDone ? "in progress" : "pending", `${s.experimentsDone}/${s.experiments} experiments completed`],171 ["Phases 7–9 — Prototypes → methodology", C.exists("research/methodology.md") ? "done" : "pending", "evidence-driven; the methodology is a primary deliverable"],172 ["Phase 10 — Atlas pipeline & this platform", "in progress", `platform live · ${s.atlasEntries} map${s.atlasEntries === 1 ? "" : "s"} published`],173 ["Phase 11 — Novelty verification", C.exists("research/novelty_check.md") ? "done" : "pending", "assume not novel until evidence suggests otherwise"],174 ];175 const phaseHtml = phases176 .map(177 ([name, st, detail]) => `<li class="phase ${st.replace(" ", "-")}">178 <span class="phase-dot"></span><div><strong>${name}</strong><span class="phase-detail">${detail}</span></div>179 <span class="badge badge-${st.replace(" ", "-")}">${st}</span></li>`180 )181 .join("");182 const logHtml = log183 .map(184 (e) => `<article class="log-entry"><h3>${R.esc(e.title)}</h3>185 <div class="md">${R.markdownToHtml(e.body.split("\n").slice(0, 8).join("\n"), "research/LOG.md")}</div>186 <a class="more" href="/doc/research/LOG.md">Full research log →</a></article>`187 )188 .join("");189190 const body = `191<section class="hero">192 <p class="kicker">Independent interpretability research · Apple Silicon</p>193 <h1>An internal cartography of<br>local large language models</h1>194 <p class="lede">Given an already-trained open-weight model, what can actually be <em>known, measured,195 localized, and mapped</em> about its internal organization — where knowledge lives, how computation196 is distributed, which structures are stable across inputs, layers, scales, and model families —197 using only a consumer-grade Mac? Every map published here is versioned, provenanced,198 confidence-labeled, and regenerable.</p>199 <p class="lede-eq"><code>what a probe reports ≠ what the model computes ≠ what is stable across methods ≠ what survives intervention</code></p>200</section>201202<section class="tiles">203 <div class="tile"><span class="tile-value">${s.sources}</span><span class="tile-label">sources reviewed</span></div>204 <div class="tile"><span class="tile-value">${s.gaps}</span><span class="tile-label">research gaps identified</span></div>205 <div class="tile"><span class="tile-value">${s.experimentsDone}<span class="tile-denom">/${s.experiments}</span></span><span class="tile-label">experiments completed</span></div>206 <div class="tile"><span class="tile-value">${s.atlasEntries}</span><span class="tile-label">atlas maps published</span></div>207</section>208209<section class="split">210 <div class="card">211 <h2>The evidence standard</h2>212 <p>A claim enters the atlas only at the confidence level its evidence supports.213 Correlational maps and causally-verified maps are never conflated — visually or textually.214 The two metrics tracked for every map are its <strong>replication rate</strong> (does it215 reproduce under resampling of seeds and data?) and its <strong>causal confirmation rate</strong>216 (what fraction of localized claims survive intervention?).</p>217 ${R.confidenceLadder()}218 <p class="note-line">Negative results — techniques whose maps do not replicate — are first-class,219 publishable findings here.</p>220 </div>221 <div class="card">222 <h2>Research phases</h2>223 <ul class="phases">${phaseHtml}</ul>224 </div>225</section>226227${(() => {228 const causal = interventionsMapCharts();229 const probe2 = probeMapCharts("agreement", MAP_V2);230 const probe1 = probeMapCharts("lang_id");231 const exph = expHCharts();232 return causal || probe1 || probe2 || exph ? `<section class="card">233 <h2>First measured maps</h2>234 <p class="lede-small">Every figure below is regenerated from committed code + versioned results —235 raw JSON with hardware manifests under <a href="/results">Results</a>. Full per-property maps live236 in the <a href="/atlas">Atlas</a>.</p>237 ${causal}${probe2}${probe1}${exph}238</section>` : "";239 })()}240241<section class="card">242 <h2>Latest from the research log</h2>243 <div class="log-grid">${logHtml || "<p>No log entries yet.</p>"}</div>244</section>`;245 page(res, { title: "Home", active: "Home", body });246});247248// ---------------------------------------------------------------- research index249app.get("/research", (req, res) => {250 const docs = [251 ["research/LOG.md", "Research log", "Append-only, auditable record of every question, experiment, result, and decision."],252 ["research/state_of_the_art.md", "State of the art", "Phase 2 — technique taxonomy with epistemic status (established / contested / debunked-in-part)."],253 ["research/research_gaps.md", "Research gaps", "Phase 3 — ≥20 falsifiable candidate directions, each with its smallest Mac-runnable falsifying experiment."],254 ["research/candidate_ranking.md", "Candidate ranking", "Phase 4 — 10-axis scoring and 3–5 selected prototype candidates."],255 ["research/methodology.md", "Methodology", "Phase 9 — the formal pipeline turning (checkpoint + corpora + budget) into confidence-labeled atlas entries."],256 ["research/novelty_check.md", "Novelty check", "Phase 11 — final novelty verification (assume not novel until shown otherwise)."],257 ["research/bibliography.md", "Bibliography", "Every consulted source with URL and access date."],258 ];259 const cards = docs260 .map(([rel, title, desc]) => {261 const ok = C.exists(rel);262 return `<a class="doc-card ${ok ? "" : "disabled"}" href="${ok ? "/doc/" + rel : "#"}">263 <h3>${title}</h3><p>${desc}</p>${ok ? "" : '<span class="badge badge-pending">not yet written</span>'}</a>`;264 })265 .join("");266 const notes = (C.listDir("research/notes") || [])267 .filter((f) => f.name.endsWith(".md") && f.name !== "README.md")268 .map((f) => {269 const md = C.readMarkdown(f.rel);270 const doc = md && md.data.document ? md.data.document : f.name;271 return `<a class="doc-card" href="/doc/${f.rel}"><h3>${R.esc(f.name.replace(".md", "").replace(/_/g, " "))}</h3>272 <p class="mono-small">${R.esc(doc)}</p></a>`;273 })274 .join("");275 const body = `<h1 class="page-title">Research documents</h1>276<div class="doc-grid">${cards}</div>277<h2 class="section-title">Phase 1 literature notes</h2>278<div class="doc-grid">${notes || '<p class="note-line">No literature notes yet — Phase 1 has not started.</p>'}</div>279<p class="note-line">The project charter itself is public: <a href="/doc/CLAUDE.md">read the full research charter</a>.</p>`;280 page(res, { title: "Research", active: "Research", body });281});282283// ---------------------------------------------------------------- markdown viewer284app.get(/^\/doc\/(.+)$/, (req, res) => {285 const rel = req.params[0];286 const md = rel.endsWith(".md") ? C.readMarkdown(rel) : null;287 if (!md) return notFound(res);288 const body = `<article class="doc">289 <p class="crumb"><a href="/research">Research</a> / ${R.esc(rel)}</p>290 ${metaChips(md.data)}291 <div class="md">${R.markdownToHtml(md.content, rel)}</div>292 </article>`;293 page(res, { title: md.data.document || rel, active: "Research", body });294});295296// ---------------------------------------------------------------- experiments297app.get("/experiments", (req, res) => {298 const exps = C.listExperiments();299 const cards = exps300 .map(301 (e) => `<a class="doc-card" href="/experiments/${e.id}">302 <h3>${R.esc(e.id)}</h3><p>${R.esc(e.purpose)}</p>303 <span class="badge badge-${e.status === "completed" ? "done" : e.status === "has results" ? "in-progress" : "pending"}">${e.status}</span>304 ${e.runs ? `<span class="runs">${e.runs} result run${e.runs > 1 ? "s" : ""}</span>` : ""}</a>`305 )306 .join("");307 const body = `<h1 class="page-title">Experiments</h1>308<p class="lede-small">Every experiment carries a registered hypothesis with an explicit falsification criterion309(seven-field scientific block), mandatory controls and nulls, raw results, and an analysis. Negative results are kept.310Micro-experiments A–H establish the noise floor, the correlational→causal survival rate, and the capture cost311frontier before any large model is mapped.</p>312<div class="doc-grid">${cards}</div>`;313 page(res, { title: "Experiments", active: "Experiments", body });314});315316app.get("/experiments/:id", (req, res) => {317 const exps = C.listExperiments();318 const exp = exps.find((e) => e.id === req.params.id);319 if (!exp) return notFound(res);320 const sections = [];321 for (const [file, title] of [["hypothesis.md", "Hypothesis"], ["analysis.md", "Analysis"], ["README.md", "README"]]) {322 const md = C.readMarkdown(path.posix.join(exp.rel, file));323 if (md && md.content.trim().length > 40) {324 sections.push(`<section class="card"><h2>${title}</h2>${metaChips(md.data)}325 <div class="md">${R.markdownToHtml(md.content, path.posix.join(exp.rel, file))}</div></section>`);326 }327 }328 const runs = C.listResultRuns().filter((r) => r.experiment === exp.id);329 const runsHtml = runs.length330 ? `<section class="card"><h2>Result runs</h2><ul class="file-list">` +331 runs.map((r) => r.files.map((f) => `<li><a href="/results/${f.rel}">${r.timestamp} / ${f.name}</a> <span class="mono-small">${(f.size / 1024).toFixed(1)} KiB</span></li>`).join("")).join("") +332 `</ul></section>`333 : "";334 const codeLink = C.exists(path.posix.join(exp.rel, "benchmark.py"))335 ? `<p><a class="more" href="/file/${exp.rel}/benchmark.py">View benchmark implementation (benchmark.py) →</a></p>`336 : "";337 let charts = "";338 if (exp.id === "expH_capture_cost_frontier") charts = expHCharts();339 if (exp.id === "expA_probe_reliability") {340 charts = probeMapCharts(null, MAP_V2) + probeMapCharts();341 }342 if (exp.id === "expC_causal_verification") charts = interventionsMapCharts();343 if (charts) charts = `<section class="card"><h2>Result maps</h2>${charts}</section>`;344 const body = `<p class="crumb"><a href="/experiments">Experiments</a> / ${R.esc(exp.id)}</p>345<h1 class="page-title">${R.esc(exp.id)}</h1><p class="lede-small">${R.esc(exp.purpose)}</p>346${codeLink}${charts}${sections.join("")}${runsHtml}`;347 page(res, { title: exp.id, active: "Experiments", body });348});349350// ---------------------------------------------------------------- atlas351app.get("/atlas", (req, res) => {352 const entries = C.listAtlasEntries();353 const byModel = {};354 for (const e of entries) (byModel[e.model] ||= []).push(e);355 const groups = Object.keys(byModel).sort().map((model) => {356 const cards = byModel[model]357 .map(358 (e) => `<a class="doc-card" href="/atlas/${e.model}/${e.mapType}/${e.version}">359 <h3>${R.esc(e.mapType)} <span class="mono-small">${R.esc(e.version)}</span></h3>360 <p>${e.provenance && e.provenance.created ? "created " + R.esc(e.provenance.created) : ""}</p>361 ${R.levelBadge(e.level)}</a>`362 )363 .join("");364 return `<h2 class="section-title">${R.esc(model)}</h2><div class="doc-grid">${cards}</div>`;365 }).join("");366 const empty = `<div class="card">367 <h2>No maps published yet</h2>368 <p>The atlas fills only after the mapping methodology exists (Phase 9) and each map clears its369 evidence bar. Every entry will carry a completed <code>provenance.json</code> (commit, config,370 model hash, hardware, dates) and a <code>confidence.md</code> stating its evidence level.371 Nothing is published that cannot be regenerated from committed code and versioned data.</p>372 ${R.confidenceLadder()}373 </div>`;374 const body = `<h1 class="page-title">Atlas</h1>375<p class="lede-small">Versioned map artifacts: <code>atlas/<model>/<map type>/<version></code>.376Only open-weight models are mapped, and no claim appears here above its evidence level.</p>377${groups || empty}`;378 page(res, { title: "Atlas", active: "Atlas", body });379});380381app.get("/atlas/:model/:mapType/:version", (req, res) => {382 const { model, mapType, version } = req.params;383 const entry = C.listAtlasEntries().find(384 (e) => e.model === model && e.mapType === mapType && e.version === version385 );386 if (!entry) return notFound(res);387 const confidence = C.readMarkdown(path.posix.join(entry.rel, "confidence.md"));388 const prov = entry.provenance389 ? `<pre class="codeblock"><code class="hljs">${R.highlightFile(JSON.stringify(entry.provenance, null, 2), "provenance.json")}</code></pre>`390 : "<p>provenance.json missing — this entry is not publishable.</p>";391 const files = entry.files392 .map((f) => `<li><a href="/results/${f.rel}">${f.name}</a> <span class="mono-small">${(f.size / 1024).toFixed(1)} KiB</span></li>`)393 .join("");394 const mapRel = path.posix.join(entry.rel, "map.json");395 const mapCharts = !C.exists(mapRel) ? "" :396 mapType === "probes" ? probeMapCharts(null, mapRel) :397 mapType === "interventions" ? interventionsMapCharts(mapRel) : "";398 const body = `<p class="crumb"><a href="/atlas">Atlas</a> / ${R.esc(entry.rel)}</p>399<h1 class="page-title">${R.esc(model)} — ${R.esc(mapType)} <span class="mono-small">${R.esc(version)}</span></h1>400<p>${R.levelBadge(entry.level)}</p>401${mapCharts ? `<section class="card"><h2>The map</h2>${mapCharts}</section>` : ""}402${confidence ? `<section class="card"><h2>Confidence</h2><div class="md">${R.markdownToHtml(confidence.content, entry.rel + "/confidence.md")}</div></section>` : ""}403<section class="card"><h2>Provenance</h2>${prov}</section>404<section class="card"><h2>Files</h2><ul class="file-list">${files}</ul></section>`;405 page(res, { title: `${model}/${mapType}/${version}`, active: "Atlas", body });406});407408// ---------------------------------------------------------------- results409app.get("/results", (req, res) => {410 const runs = C.listResultRuns();411 const rows = runs412 .map(413 (r) => `<tr><td><a href="/experiments/${r.experiment}">${r.experiment}</a></td>414 <td class="mono-small">${r.timestamp}</td>415 <td>${r.files.map((f) => `<a href="/results/${f.rel}">${f.name}</a>`).join(" · ")}</td></tr>`416 )417 .join("");418 const body = `<h1 class="page-title">Raw results</h1>419<p class="lede-small">Every result is reproducible from commit hash + config + model hash + seed +420hardware manifest, and each JSON embeds the manifest of the exact machine that produced it.</p>421<table class="results-table"><thead><tr><th>Experiment</th><th>Run (UTC)</th><th>Files</th></tr></thead>422<tbody>${rows || '<tr><td colspan="3">No result runs yet.</td></tr>'}</tbody></table>`;423 page(res, { title: "Results", active: "Results", body });424});425426app.get(/^\/results\/(.+)$/, (req, res) => {427 const raw0 = req.params[0];428 const rel = raw0.startsWith("results/") || raw0.startsWith("atlas/") ? raw0 : "results/" + raw0;429 const raw = C.readText(rel);430 if (raw === null) return notFound(res);431 let bodyContent;432 if (rel.endsWith(".json")) {433 const obj = C.readJson(rel);434 bodyContent = `<pre class="codeblock"><code class="hljs">${R.highlightFile(JSON.stringify(obj, null, 2), "x.json")}</code></pre>`;435 } else {436 bodyContent = `<pre class="codeblock"><code>${R.esc(raw.slice(0, 200000))}</code></pre>`;437 }438 const body = `<p class="crumb"><a href="/results">Results</a> / ${R.esc(rel)}</p><div class="card">${bodyContent}</div>`;439 page(res, { title: rel, active: "Results", body });440});441442// ---------------------------------------------------------------- code browser443const CODE_ROOTS = ["src", "tools", "benchmarks", "experiments", "Makefile", "pyproject.toml", "CITATION.cff"];444app.get("/code", (req, res) => {445 const sections = CODE_ROOTS.map((root) => {446 if (!C.exists(root)) return "";447 const st = C.listDir(root);448 if (st === null) {449 return `<li><a href="/file/${root}">${root}</a></li>`;450 }451 const files = C.walk(root, (f) => C.isTextFile(f.rel) && !f.rel.includes("results/"));452 return `<li class="tree-root"><strong>${root}/</strong><ul>` +453 files.map((f) => `<li><a href="/file/${f.rel}">${f.rel.slice(root.length + 1)}</a></li>`).join("") +454 `</ul></li>`;455 }).join("");456 const body = `<h1 class="page-title">Code</h1>457<p class="lede-small">The mapping library (<code>src/modelmap/</code>), tooling, benchmark harness, and experiment458implementations. Every file carries the project's author header; MLX / PyTorch-MPS / Metal is the primary compute459path — CUDA is never a core dependency.</p>460<ul class="tree">${sections}</ul>`;461 page(res, { title: "Code", active: "Code", body });462});463464app.get(/^\/file\/(.+)$/, (req, res) => {465 const rel = req.params[0];466 if (!C.isTextFile(rel)) return notFound(res);467 const raw = C.readText(rel);468 if (raw === null) return notFound(res);469 const name = rel.split("/").pop();470 const body = `<p class="crumb"><a href="/code">Code</a> / ${R.esc(rel)}</p>471<div class="card file-card"><div class="file-head"><span class="mono-small">${R.esc(rel)}</span>472<span class="mono-small">${raw.split("\n").length} lines</span></div>473<pre class="codeblock"><code class="hljs">${R.highlightFile(raw.slice(0, 400000), name)}</code></pre></div>`;474 page(res, { title: name, active: "Code", body });475});476477// ---------------------------------------------------------------- about478app.get("/about", (req, res) => {479 const questions = [480 ["Q1 — Localization", "Where inside a pretrained LLM do capabilities, knowledge domains, languages, and behaviors reside? Localized (layers, heads, neurons, weight blocks, directions) or diffuse?"],481 ["Q2 — Structure", "Which stable internal structures exist across inputs — circuits, feature directions, attention patterns, activation manifolds, weight-space geometry — and at what granularity are they real rather than artifacts of the probing method?"],482 ["Q3 — Comparability", "Can internal maps be compared across model sizes, checkpoints, quantization levels, and families? Is there a common coordinate system for model internals?"],483 ["Q4 — Cost", "Which mapping techniques are feasible on a 16–64 GB Mac, at which model sizes, and what is the accuracy/cost frontier of local interpretability?"],484 ["Q5 — Utility", "Do the maps predict anything useful — quantization sensitivity, pruning tolerance, working-set behavior, failure modes, editing targets?"],485 ];486 const qHtml = questions487 .map(([q, d]) => `<tr><th>${q}</th><td>${d}</td></tr>`)488 .join("");489 const body = `<h1 class="page-title">About this project</h1>490<div class="card md">491<p><strong>modelmap</strong> is an independent research project by492<strong>Simon-Pierre Boucher</strong> (<a href="mailto:contact@spboucher.ai">contact@spboucher.ai</a>) building a493systematic methodology — and the tooling behind it — to discover, measure, and map the internal structure of494pretrained open-weight LLMs running locally on consumer Apple Silicon hardware, and publishing the resulting maps495as a rigorous, reproducible public atlas on this site.</p>496<p>The ideal outcome is not a gallery of suggestive visualizations. It is a <strong>reproducible cartographic497standard for open-weight models</strong> — every map versioned, provenanced, confidence-labeled, and regenerable498by anyone with a Mac — turning “we think the model does X” into “here is the map, its evidence level, and the499script that rebuilds it.”</p>500<h2>Core research questions</h2>501<table class="kv-table">${qHtml}</table>502<h2>The evidence standard</h2>503${R.confidenceLadder()}504<p>Every mapping technique runs with controls: shuffled labels for probes, random-direction baselines for steering,505randomly-initialized-model baselines where meaningful, resample vs zero ablations. Structure is never claimed506without showing the null. Replication across ≥3 seeds and ≥2 prompt sets, bootstrap confidence intervals, effect507sizes, and multiple-comparison correction are mandatory for every published number.</p>508<h2>Target hardware</h2>509<p>Apple Silicon Mac (M1–M4 family), 16–64 GB unified memory, internal NVMe SSD, Metal GPU sharing memory with the510CPU. Local interpretability on consumer hardware is itself an under-served niche: most tooling assumes CUDA511clusters. Making rigorous mapping feasible on a Mac is part of the contribution. The stretch target is a full,512causally-verified, versioned atlas of a 7B–14B model produced end-to-end on a single 32–64 GB Mac, comparable513across ≥2 quantization levels and ≥2 model sizes.</p>514<h2>Sister project</h2>515<p><a href="https://www.localvm.dev">localvm-research</a> investigates out-of-core LLM execution on the same516hardware class — running models larger than memory. The projects cross-pollinate: modelmap's working-set and517localization maps (Q5) feed localvm's execution decisions, and localvm's cost measurements calibrate modelmap's518capture-feasibility frontier (Experiment H).</p>519<p>Failure is an acceptable outcome — the charter defines explicit failure criteria, and the520<a href="/doc/research/LOG.md">log</a> records why an approach died, not just what survived.</p>521</div>`;522 page(res, { title: "About", active: "About", body });523});524525// ---------------------------------------------------------------- publications526const FIGS = {527 "causal-band": () => interventionsMapCharts(),528 "probes-agreement": () => probeMapCharts("agreement", MAP_V2),529 "probes-arith": () => probeMapCharts("arith_valid", MAP_V2),530 "probes-word-order": () => probeMapCharts("word_order", MAP_V2),531 "probes-null": () => probeMapCharts("lang_id"),532 "storage": () => storageChart(),533 "capture": () => captureChart(),534};535536function listPublications() {537 return (C.listDir("publications") || [])538 .filter((f) => f.name.endsWith(".md"))539 .map((f) => {540 const md = C.readMarkdown(f.rel);541 return md ? { rel: f.rel, id: f.name.replace(".md", ""), data: md.data } : null;542 })543 .filter(Boolean)544 .sort((a, b) => String(b.data.created).localeCompare(String(a.data.created)));545}546547app.get("/publications", (req, res) => {548 const pubs = listPublications();549 const cards = pubs.map((p) => `<a class="pub-card" href="/publications/${p.id}">550 <div class="pub-card-meta"><span class="pub-id">${R.esc(p.data.pub_id || p.id)}</span>551 <span class="badge badge-${p.data.status === "final" ? "done" : "in-progress"}">${R.esc(p.data.status || "draft")}</span>552 <span class="pub-date">${R.esc(String(p.data.created))}</span></div>553 <h3>${R.esc(p.data.title || p.id)}</h3>554 <p>${R.esc(p.data.abstract ? String(p.data.abstract).slice(0, 300) + "…" : "")}</p>555 <span class="more">Read the report →</span></a>`).join("");556 const body = `<h1 class="page-title">Publications</h1>557<p class="lede-small">Official technical reports of this project. Every number is regenerable from558the stated commit; figures are rendered live from the same versioned results as the559<a href="/atlas">Atlas</a>; negative results and publication-gate refusals are reported560with the same prominence as positive findings.</p>561${cards || '<p class="note-line">No publications yet.</p>'}`;562 page(res, { title: "Publications", active: "Publications", body });563});564565app.get("/publications/:id", (req, res) => {566 const rel = `publications/${req.params.id}.md`;567 const md = C.readMarkdown(rel);568 if (!md) return notFound(res);569 let html = R.markdownToHtml(md.content, rel);570 html = html.replace(/<p>\{\{fig:([a-z0-9-]+)\}\}<\/p>/g, (_, key) =>571 FIGS[key] ? FIGS[key]() : "");572 const d = md.data;573 const body = `<article class="doc pub">574 <p class="crumb"><a href="/publications">Publications</a> / ${R.esc(d.pub_id || req.params.id)}</p>575 <header class="pub-head">576 <div class="pub-card-meta"><span class="pub-id">${R.esc(d.pub_id || req.params.id)}</span>577 <span class="badge badge-${d.status === "final" ? "done" : "in-progress"}">${R.esc(d.status || "draft")}</span>578 <span class="pub-date">${R.esc(String(d.created))}</span></div>579 <h1>${R.esc(d.title || req.params.id)}</h1>580 <p class="pub-byline">${R.esc(d.author || "Simon-Pierre Boucher")} ·581 <a href="mailto:${R.esc(d.contact || "contact@spboucher.ai")}">${R.esc(d.contact || "contact@spboucher.ai")}</a> ·582 <a href="https://modelmap.io">modelmap.io</a></p>583 ${d.abstract ? `<div class="pub-abstract"><strong>Abstract.</strong> ${R.esc(String(d.abstract))}</div>` : ""}584 </header>585 <div class="md">${html}</div>586 ${d.cite ? `<div class="pub-cite"><strong>How to cite</strong><pre class="codeblock"><code>${R.esc(String(d.cite))}</code></pre></div>` : ""}587</article>`;588 page(res, { title: d.title || req.params.id, active: "Publications", body });589});590591// ---------------------------------------------------------------- comments592function commentsPage(res, { flash = "", flashKind = "ok" } = {}) {593 const items = Comments.list();594 const listHtml = items.length595 ? `<ul class="comment-list">` + items.map((c) => `<li class="comment">596 <div class="comment-head"><span class="comment-name">${R.esc(c.name)}</span>597 <span class="comment-date">${R.esc(String(c.created).slice(0, 10))}</span></div>598 <div class="comment-body">${R.esc(c.message)}</div></li>`).join("") + `</ul>`599 : `<p class="note-line">No comments yet — be the first.</p>`;600 const body = `<h1 class="page-title">Comments</h1>601<p class="lede-small">Questions, critiques, replication reports, pointers to related work — all welcome.602Methodological challenges are especially valued: this project publishes its negative results,603and a comment that breaks a map is a contribution.</p>604${flash ? `<div class="flash flash-${flashKind}">${R.esc(flash)}</div>` : ""}605<section class="card">606 <h2>Leave a comment</h2>607 <form class="comment-form" method="POST" action="/comments">608 <div><label for="c-name">Name (optional)</label>609 <input type="text" id="c-name" name="name" maxlength="60" autocomplete="name" placeholder="Your name"></div>610 <div class="hp-field" aria-hidden="true"><label for="c-website">Website</label>611 <input type="text" id="c-website" name="website" tabindex="-1" autocomplete="off"></div>612 <div><label for="c-message">Comment</label>613 <textarea id="c-message" name="message" maxlength="2000" required614 placeholder="Your comment — plain text, max 2000 characters"></textarea></div>615 <button class="btn" type="submit">Post comment</button>616 </form>617</section>618<h2 class="section-title">${items.length ? items.length + " comment" + (items.length > 1 ? "s" : "") : "Comments"}</h2>619${listHtml}`;620 page(res, { title: "Comments", active: "Comments", body });621}622623app.get("/comments", (req, res) => {624 const flash = req.query.ok === "1" ? "Thank you — your comment is published." :625 req.query.err ? String(req.query.err) : "";626 commentsPage(res, { flash, flashKind: req.query.ok === "1" ? "ok" : "err" });627});628629app.post("/comments", (req, res) => {630 const out = Comments.add({631 name: req.body.name,632 message: req.body.message,633 honeypot: req.body.website,634 ip: req.ip,635 });636 if (out.ok) return res.redirect(303, "/comments?ok=1");637 return res.redirect(303, "/comments?err=" + encodeURIComponent(out.error || "Could not post."));638});639640// ---------------------------------------------------------------- misc641app.get("/health", (req, res) => res.json({ ok: true, app: "modelmap-web", author: "Simon-Pierre Boucher", website: "https://modelmap.io" }));642643function notFound(res) {644 res.status(404);645 page(res, { title: "Not found", active: "", body: `<div class="card"><h1>404</h1><p>That page does not exist. <a href="/">Back to home</a>.</p></div>` });646}647app.use((req, res) => notFound(res));648649app.listen(PORT, () => console.log(`modelmap-web listening on :${PORT}`));650