SPB Git

spb/anomaly-atlas Public License

Systematic discovery & rigorous validation of statistical anomalies in open HF market data (hfmarketdata.io) — pre-registered, artifact-null-driven, fully reproducible. Live atlas: www.anomaly-atlas.io

Python 61.4% JavaScript 28.7% CSS 8.6% Shell 0.7% Makefile 0.5%
30.7 KB · 554 lines javascript
Raw Blame History
1// ============================================================================2//  Project   : anomaly-atlas3//  File      : web/server.js4//  Purpose   : Public atlas platform — routes and pages (English, light)5//  Author    : Simon-Pierre Boucher6//  Contact   : contact@spboucher.ai7//  Data src  : hfmarketdata.io (sole data source)8//  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 fs = require("fs");16const os = require("os");17const path = require("path");18const express = require("express");19const C = require("./lib/content");20const R = require("./lib/render");21const charts = require("./lib/charts");2223const app = express();24const PORT = process.env.PORT || 8150;2526// Comments live OUTSIDE the deploy directory so rsync --delete redeploys27// never erase them.28const COMMENTS_PATH =29  process.env.COMMENTS_PATH || path.join(os.homedir(), ".anomaly-atlas", "comments.json");3031app.use("/static", express.static(path.join(__dirname, "public"), { maxAge: "1h" }));32app.use(express.urlencoded({ extended: false, limit: "16kb" }));3334function page(res, opts) {35  res.send(R.layout({ ...opts, buildInfo: C.buildInfo() }));36}3738function metaChips(data) {39  if (!data || !Object.keys(data).length) return "";40  const fields = ["document", "author", "created", "modified", "status"];41  const chips = fields42    .filter((f) => data[f])43    .map((f) => `<span class="chip"><span class="chip-k">${f}</span>${R.esc(data[f])}</span>`)44    .join("");45  return chips ? `<div class="chips">${chips}</div>` : "";46}4748// ---------------------------------------------------------------- home49app.get("/", (req, res) => {50  const s = C.stats();51  const log = C.parseLogEntries().slice(-3).reverse();52  const phases = [53    ["Phase 0.5 — Data reality check (Experiment A)", C.exists("research/data_source_profile.md") && (C.readText("research/data_source_profile.md") || "").length > 1200 ? "done" : "pending", "what hfmarketdata.io actually provides"],54    ["Phase 1 — Literature research (§4.1–4.6)", s.notes ? "in progress" : "pending", `${s.notes} theme notes · ${s.sources} sources`],55    ["Phase 2 — State-of-the-art map", (C.readText("research/state_of_the_art.md") || "").length > 1200 ? "done" : "pending", "per-anomaly epistemic status"],56    ["Phase 3 — Research gaps", s.gaps ? "done" : "pending", `${s.gaps || "≥20 target"} testable hypotheses with constructable artifact nulls`],57    ["Phase 4 — Candidate ranking", (C.readText("research/candidate_ranking.md") || "").length > 1200 ? "done" : "pending", "10-axis scoring, 3–5 candidates"],58    ["Phases 5–6 — Framework & micro-experiments A–H", s.experimentsDone ? "in progress" : "pending", `${s.experimentsDone}/${s.experiments} experiments completed`],59    ["Phases 7–11 — Candidates → methodology → atlas → novelty", "pending", "evidence-driven"],60  ];61  const phaseHtml = phases62    .map(63      ([name, st, detail]) => `<li class="phase ${st.replace(" ", "-")}">64        <span class="phase-dot"></span><div><strong>${name}</strong><span class="phase-detail">${detail}</span></div>65        <span class="badge badge-${st.replace(" ", "-")}">${st}</span></li>`66    )67    .join("");68  const logHtml = log69    .map((e) => {70      const [when, ...rest] = e.title.split(" — ");71      const excerpt = R.markdownToHtml(e.body.split("\n").slice(0, 6).join("\n"), "research/LOG.md").html;72      return `<article class="log-entry">73      <time class="tl-time">${R.esc(rest.length ? when : "")}</time>74      <h3>${R.esc(rest.join(" — ") || when)}</h3>75      <div class="md md-compact">${excerpt}</div></article>`;76    })77    .join("");7879  const body = `80<section class="hero">81  <p class="kicker">Independent statistics + market-microstructure research · Apple Silicon · hfmarketdata.io</p>82  <h1>Which market "anomalies" are real —<br>and which are artifacts?</h1>83  <p class="lede">A systematic, reproducible atlas of statistical regularities in open high-frequency84  market data — mean-reversion, lead-lag, calendar effects — where every claim survives (or visibly fails)85  out-of-sample testing, multiple-comparison correction, artifact nulls, and realistic transaction costs.86  Negative results are first-class findings.</p>87  <p class="lede-eq"><code>detectable in-sample ≠ reproducible out-of-sample ≠ robust to artifacts ≠ meaningful after costs</code></p>88</section>8990<section class="tiles">91  <div class="tile"><span class="tile-value">${s.sources}</span><span class="tile-label">sources reviewed</span></div>92  <div class="tile"><span class="tile-value">${s.gaps}</span><span class="tile-label">hypotheses registered</span></div>93  <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>94  <div class="tile"><span class="tile-value">${s.findings}</span><span class="tile-label">atlas findings (Level ≥ 1)</span></div>95</section>9697<section class="split">98  <div class="card">99    <h2>The confidence taxonomy</h2>100    <p>A finding only advances one level at a time, and only Level ≥ 1 is ever published.101    A large in-sample effect with zero out-of-sample survival is a <strong>negative result</strong> —102    published as one.</p>103    <ul class="phases">104      <li class="phase pending"><span class="phase-dot"></span><div><strong>Level 0 — in-sample only</strong><span class="phase-detail">scan output; never published as a finding</span></div></li>105      <li class="phase in-progress"><span class="phase-dot"></span><div><strong>Level 1 — corrected &amp; OOS</strong><span class="phase-detail">survives multiple-testing correction and a clean out-of-sample split, artifact null subtracted</span></div></li>106      <li class="phase in-progress"><span class="phase-dot"></span><div><strong>Level 2 — robust</strong><span class="phase-detail">+ robust to specification choices, sub-periods, instruments</span></div></li>107      <li class="phase done"><span class="phase-dot"></span><div><strong>Level 3 — cost-real &amp; held-out</strong><span class="phase-detail">+ economically nonzero after realistic costs, confirmed on the once-touched holdout</span></div></li>108    </ul>109    <a class="more" href="/atlas">Browse the atlas →</a>110  </div>111  <div class="card">112    <h2>Research phases</h2>113    <ul class="phases">${phaseHtml}</ul>114  </div>115</section>116117<section class="card">118  <div class="card-head-row"><h2>Latest from the research log</h2>119  <a class="more" href="/doc/research/LOG.md">Full research log →</a></div>120  <div class="log-grid">${logHtml}</div>121</section>`;122  const homeFig = charts.homeFigure(C);123  const figSection = homeFig124    ? `<section class="card">125  <div class="card-head-row"><h2>Latest measured figure</h2>126  <a class="more" href="/experiments/${homeFig.experiment}">${homeFig.experiment} →</a></div>127  ${homeFig.html}128</section>`129    : "";130  page(res, { title: "Home", active: "Home", body: body + figSection });131});132133// ---------------------------------------------------------------- atlas134app.get("/atlas", (req, res) => {135  const findings = C.listFindings();136  const published = findings.filter((f) => f.level >= 1);137  const cards = published138    .map(139      (f) => `<a class="doc-card" href="/atlas/${f.id}/${f.version}">140      <h3>${R.esc(f.title)}${f.negative ? ' <span class="badge badge-pending">negative result</span>' : ""}</h3>141      <p>${R.esc(f.summary)}</p>${R.levelBadge(f.level)}</a>`142    )143    .join("");144  const empty = `<div class="card"><h2>No findings yet — and that is the point</h2>145    <p>The atlas publishes only Level ≥ 1 findings: effects that survive multiple-testing correction146    and a clean out-of-sample split with the artifact null subtracted. Nothing has earned that yet —147    the framework is being built so that nothing can enter without earning it. The148    <a href="/doc/research/artifact_taxonomy.md">artifact taxonomy</a> and the149    <a href="/doc/research/methodology.md">validation methodology</a> are primary deliverables in their own right.</p></div>`;150  const body = `<h1 class="page-title">The atlas</h1>151<p class="lede-small">Confidence-labeled statistical regularities (and non-regularities) in hfmarketdata.io data.152Every entry carries provenance — commit, config, data-manifest hash, hardware — and the exact command that153regenerates it. Negative results are first-class entries.</p>154${published.length ? `<div class="doc-grid">${cards}</div>` : empty}155<h2 class="section-title">Foundations</h2>156<div class="doc-grid">157  <a class="doc-card" href="/doc/research/artifact_taxonomy.md"><h3>Artifact taxonomy</h3>158    <p>The catalogue of artifacts in this dataset that masquerade as anomalies — often the most useful output.</p></a>159  <a class="doc-card" href="/doc/research/methodology.md"><h3>Validation methodology</h3>160    <p>The pre-registered protocol that turns a hypothesis into a confidence-labeled entry.</p></a>161</div>`;162  page(res, { title: "Atlas", active: "Atlas", body });163});164165app.get("/atlas/:id/:version", (req, res) => {166  const f = C.listFindings().find((x) => x.id === req.params.id && x.version === req.params.version);167  if (!f) return notFound(res);168  const prov = C.readJson(path.posix.join(f.rel, "provenance.json")) || {};169  const conf = C.readMarkdown(path.posix.join(f.rel, "confidence.md"));170  const provRows = Object.entries(prov)171    .map(([k, v]) => `<tr><th>${R.esc(k)}</th><td class="mono-small">${R.esc(typeof v === "string" ? v : JSON.stringify(v))}</td></tr>`)172    .join("");173  const body = `<p class="crumb"><a href="/atlas">Atlas</a> / ${R.esc(f.id)} / ${R.esc(f.version)}</p>174<h1 class="page-title">${R.esc(f.title)}</h1>175<p>${R.levelBadge(f.level)}${f.negative ? ' <span class="badge badge-pending">negative result</span>' : ""}</p>176<p class="lede-small">${R.esc(f.summary)}</p>177${conf ? `<section class="card"><h2>Confidence evidence</h2><div class="md">${R.markdownToHtml(conf.content, path.posix.join(f.rel, "confidence.md")).html}</div></section>` : ""}178<section class="card"><h2>Finding payload</h2>179<pre class="codeblock"><code class="hljs">${R.highlightFile(JSON.stringify(f.finding, null, 2), "x.json")}</code></pre></section>180<section class="card"><h2>Provenance</h2><table class="kv-table">${provRows}</table></section>181<p class="note-line">Past statistical regularity does not imply future returns. Not investment advice.</p>`;182  page(res, { title: f.title, active: "Atlas", body });183});184185// ---------------------------------------------------------------- publications186function listPublications() {187  return (C.listDir("research/publications") || [])188    .filter((f) => f.name.endsWith(".md") && f.name !== "README.md")189    .map((f) => {190      const md = C.readMarkdown(f.rel);191      return md ? { rel: f.rel, slug: f.name.replace(/\.md$/, ""), data: md.data,192                    content: md.content } : null;193    })194    .filter(Boolean)195    .sort((a, b) => String(b.data.created).localeCompare(String(a.data.created)));196}197198app.get("/publications", (req, res) => {199  const pubs = listPublications();200  const cards = pubs.map((p) => `<a class="doc-card pub-card" href="/publications/${p.slug}">201    <span class="pub-id">${R.esc(p.data.pub_id || "")} · ${R.esc(String(p.data.created || ""))} · v${R.esc(String(p.data.version || "1"))}</span>202    <h3>${R.esc(p.data.title || p.slug)}</h3>203    ${p.data.subtitle ? `<p class="pub-sub">${R.esc(p.data.subtitle)}</p>` : ""}204    <p>${R.esc(p.data.abstract ? String(p.data.abstract).slice(0, 260) + "…" : "")}</p>205    <span class="badge badge-${p.data.status === "published" ? "done" : "in-progress"}">${R.esc(p.data.status || "draft")}</span></a>`).join("");206  const body = `<h1 class="page-title">Publications</h1>207<p class="lede-small">Formal write-ups of the project's results, versioned in the repository like everything208else. Every number is regenerated from committed <code>results.json</code> files and every figure is rendered209live from them — nothing is hand-typed. Each publication states its evidence level; negative results are210published with the same care as positive ones.</p>211<div class="doc-grid pub-grid">${cards || '<p class="lede-small">No publications yet.</p>'}</div>`;212  page(res, { title: "Publications", active: "Publications", body });213});214215app.get("/publications/:slug", (req, res) => {216  const pub = listPublications().find((p) => p.slug === req.params.slug);217  if (!pub) return notFound(res);218  let { html, toc } = R.markdownToHtml(pub.content, pub.rel);219  // live figures: {{figure:experiment_id}} tokens -> server-rendered SVG220  html = html.replace(/<p>\s*\{\{figure:([\w-]+)\}\}\s*<\/p>|\{\{figure:([\w-]+)\}\}/g,221    (m, a, b) => charts.figuresFor(a || b, C) || "");222  const d = pub.data;223  const body = `<article class="pub">224<header class="pub-head">225  <p class="pub-id">${R.esc(d.pub_id || "")} · version ${R.esc(String(d.version || "1"))} · ${R.esc(String(d.created || ""))}</p>226  <h1>${R.esc(d.title || pub.slug)}</h1>227  ${d.subtitle ? `<p class="pub-subtitle">${R.esc(d.subtitle)}</p>` : ""}228  <p class="pub-meta">${R.esc(d.author || "")} · <a href="mailto:${R.esc(d.contact || "")}">${R.esc(d.contact || "")}</a>229  · data: <a href="https://www.hfmarketdata.io">hfmarketdata.io</a>230  <span class="badge badge-${d.status === "published" ? "done" : "in-progress"}">${R.esc(d.status || "draft")}</span></p>231  ${d.abstract ? `<div class="abstract"><span class="abstract-k">Abstract</span><p>${R.esc(d.abstract)}</p></div>` : ""}232</header>233<div class="doc-layout ${toc.length >= 3 ? "has-toc" : ""}">234  ${R.tocHtml(toc)}235  <div class="doc"><div class="md pub-body">${html}</div></div>236</div>237<footer class="pub-footer">Not investment advice. Past statistical regularity does not imply future returns.238Reproducible from the repository at the commits cited above; every figure regenerates from committed results.</footer>239</article>`;240  page(res, { title: d.title || pub.slug, active: "Publications", body });241});242243// ---------------------------------------------------------------- research index244app.get("/research", (req, res) => {245  const docs = [246    ["research/LOG.md", "Research log", "Append-only, auditable record of every question, experiment, result, and decision."],247    ["research/data_source_profile.md", "Data source profile", "Phase 0.5 — what hfmarketdata.io actually provides, established empirically."],248    ["research/state_of_the_art.md", "State of the art", "Phase 2 — per-anomaly map with epistemic status: robust / decayed / disputed / likely-artifact."],249    ["research/artifact_taxonomy.md", "Artifact taxonomy", "The living catalogue of dataset artifacts that masquerade as anomalies (Q4)."],250    ["research/research_gaps.md", "Research gaps", "Phase 3 — ≥20 testable hypotheses, each with a constructable artifact null."],251    ["research/candidate_ranking.md", "Candidate ranking", "Phase 4 — 10-axis scoring and selected prototype candidates."],252    ["research/methodology.md", "Validation methodology", "Phase 9 — the pre-registered protocol behind every atlas entry."],253    ["research/bibliography.md", "Bibliography", "Every consulted source with URL and access date."],254    ["research/novelty_check.md", "Novelty check", "Phase 11 — assume not novel until evidence says otherwise (written last)."],255  ];256  const cards = docs257    .map(([rel, title, desc]) => {258      const ok = C.exists(rel);259      const thin = ok && (C.readText(rel) || "").length < 1200;260      return `<a class="doc-card ${ok ? "" : "disabled"}" href="${ok ? "/doc/" + rel : "#"}">261        <h3>${title}</h3><p>${desc}</p>${!ok ? '<span class="badge badge-pending">not yet written</span>' : thin ? '<span class="badge badge-pending">placeholder</span>' : ""}</a>`;262    })263    .join("");264  const notes = (C.listDir("research/notes") || [])265    .filter((f) => f.name.endsWith(".md") && f.name !== "README.md")266    .map((f) => {267      const md = C.readMarkdown(f.rel);268      const sources = md ? (md.content.match(/^- .*http/gm) || []).length : 0;269      const lines = md ? md.content.split("\n").length : 0;270      return `<a class="doc-card" href="/doc/${f.rel}"><h3>${R.esc(f.name.replace(".md", "").replace(/_/g, " "))}</h3>271        <p>Phase 1 literature notes — ${lines} lines.</p>272        <span class="badge badge-done">${sources} sources</span></a>`;273    })274    .join("");275  const body = `<h1 class="page-title">Research documents</h1>276<div class="doc-grid">${cards}</div>277${notes ? `<h2 class="section-title">Phase 1 literature notes</h2><div class="doc-grid">${notes}</div>` : ""}278<p class="note-line">The project charter itself is public: <a href="/doc/CLAUDE.md">read the full research charter</a>.</p>`;279  page(res, { title: "Research", active: "Research", body });280});281282// ---------------------------------------------------------------- markdown viewer283app.get(/^\/doc\/(.+)$/, (req, res) => {284  const rel = req.params[0];285  const md = rel.endsWith(".md") ? C.readMarkdown(rel) : null;286  if (!md) return notFound(res);287  const crumb = `<p class="crumb"><a href="/research">Research</a> / ${R.esc(rel)}</p>`;288289  if (rel === "research/LOG.md") {290    const entries = C.parseLogEntries();291    const body = `${crumb}292      ${R.docHeader({ ...md.data, document: "Research log" }, rel)}293      <p class="lede-small">Append-only, newest first — every question, experiment, result,294      interpretation, and decision, as required by the charter (§12). ${entries.length} entries.</p>295      ${R.logTimeline(entries, rel)}`;296    return page(res, { title: "Research log", active: "Research", body });297  }298299  const { html, toc } = R.markdownToHtml(md.content, rel);300  const tocBox = R.tocHtml(toc);301  const body = `${crumb}${R.docHeader(md.data, rel)}302  <div class="doc-layout ${tocBox ? "has-toc" : ""}">303    ${tocBox}304    <article class="doc"><div class="md">${html}</div></article>305  </div>`;306  page(res, { title: md.data.document || rel, active: "Research", body });307});308309// ---------------------------------------------------------------- experiments310app.get("/experiments", (req, res) => {311  const exps = C.listExperiments();312  const cards = exps313    .map(314      (e) => `<a class="doc-card" href="/experiments/${e.id}">315      <h3>${R.esc(e.id)}</h3><p>${R.esc(e.purpose)}</p>316      <span class="badge badge-${e.status === "completed" ? "done" : e.status === "has results" ? "in-progress" : "pending"}">${e.status}</span>317      ${e.runs ? `<span class="runs">${e.runs} result run${e.runs > 1 ? "s" : ""}</span>` : ""}</a>`318    )319    .join("");320  const body = `<h1 class="page-title">Experiments</h1>321<p class="lede-small">Every experiment carries a registered hypothesis with an explicit falsification criterion322and its artifact null(s), a benchmark implementation, raw results, and an analysis. Detectors must first pass the323synthetic-series tests — a detector that finds anomalies in a random walk is broken. Negative results are kept.</p>324<div class="doc-grid">${cards}</div>`;325  page(res, { title: "Experiments", active: "Experiments", body });326});327328app.get("/experiments/:id", (req, res) => {329  const exps = C.listExperiments();330  const exp = exps.find((e) => e.id === req.params.id);331  if (!exp) return notFound(res);332  const sections = [];333  for (const [file, title] of [["hypothesis.md", "Hypothesis"], ["analysis.md", "Analysis"], ["README.md", "README"]]) {334    const md = C.readMarkdown(path.posix.join(exp.rel, file));335    if (md && md.content.trim().length > 40) {336      sections.push(`<section class="card"><h2>${title}</h2>${metaChips(md.data)}337        <div class="md">${R.markdownToHtml(md.content, path.posix.join(exp.rel, file)).html}</div></section>`);338    }339  }340  const runs = C.listResultRuns().filter((r) => r.experiment === exp.id);341  const runsHtml = runs.length342    ? `<section class="card"><h2>Result runs</h2><ul class="file-list">` +343      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("") +344      `</ul></section>`345    : "";346  const codeLink = C.exists(path.posix.join(exp.rel, "benchmark.py"))347    ? `<p><a class="more" href="/file/${exp.rel}/benchmark.py">View benchmark implementation (benchmark.py) →</a></p>`348    : "";349  const figures = charts.figuresFor(exp.id, C);350  const figuresHtml = figures351    ? `<section class="card"><h2>Figures</h2><p class="lede-small">Generated server-side from the latest committed <code>results.json</code> — never hand-typed.</p>${figures}</section>`352    : "";353  const body = `<p class="crumb"><a href="/experiments">Experiments</a> / ${R.esc(exp.id)}</p>354<h1 class="page-title">${R.esc(exp.id)}</h1><p class="lede-small">${R.esc(exp.purpose)}</p>355${codeLink}${figuresHtml}${sections.join("")}${runsHtml}`;356  page(res, { title: exp.id, active: "Experiments", body });357});358359// ---------------------------------------------------------------- results360app.get("/results", (req, res) => {361  const runs = C.listResultRuns();362  const rows = runs363    .map(364      (r) => `<tr><td><a href="/experiments/${r.experiment}">${r.experiment}</a></td>365      <td class="mono-small">${r.timestamp}</td>366      <td>${r.files.map((f) => `<a href="/results/${f.rel}">${f.name}</a>`).join(" · ")}</td></tr>`367    )368    .join("");369  const body = `<h1 class="page-title">Raw results</h1>370<p class="lede-small">Every result is reproducible from commit hash + config + data-manifest index + seed +371hardware manifest, and each JSON embeds the manifest of the exact machine that produced it.</p>372<table class="results-table"><thead><tr><th>Experiment</th><th>Run (UTC)</th><th>Files</th></tr></thead>373<tbody>${rows || '<tr><td colspan="3">No result runs yet.</td></tr>'}</tbody></table>`;374  page(res, { title: "Results", active: "Results", body });375});376377app.get(/^\/results\/(.+)$/, (req, res) => {378  const rel = req.params[0].startsWith("results/") ? req.params[0] : "results/" + req.params[0];379  const raw = C.readText(rel);380  if (raw === null) return notFound(res);381  let bodyContent;382  if (rel.endsWith(".json")) {383    const obj = C.readJson(rel);384    bodyContent = `<pre class="codeblock"><code class="hljs">${R.highlightFile(JSON.stringify(obj, null, 2), "x.json")}</code></pre>`;385  } else {386    bodyContent = `<pre class="codeblock"><code>${R.esc(raw.slice(0, 200000))}</code></pre>`;387  }388  const body = `<p class="crumb"><a href="/results">Results</a> / ${R.esc(rel)}</p><div class="card">${bodyContent}</div>`;389  page(res, { title: rel, active: "Results", body });390});391392// ---------------------------------------------------------------- code browser393const CODE_ROOTS = ["src", "tools", "benchmarks", "experiments", "Makefile", "pyproject.toml", "CITATION.cff"];394app.get("/code", (req, res) => {395  const sections = CODE_ROOTS.map((root) => {396    if (!C.exists(root)) return "";397    const st = C.listDir(root);398    if (st === null) {399      return `<li><a href="/file/${root}">${root}</a></li>`;400    }401    const files = C.walk(root, (f) => C.isTextFile(f.rel) && !f.rel.includes("results/"));402    return `<li class="tree-root"><strong>${root}/</strong><ul>` +403      files.map((f) => `<li><a href="/file/${f.rel}">${f.rel.slice(root.length + 1)}</a></li>`).join("") +404      `</ul></li>`;405  }).join("");406  const body = `<h1 class="page-title">Code</h1>407<p class="lede-small">Core library (<code>src/anomaly_atlas/</code>) — including the single408<code>hf_client</code> every byte of data flows through — tooling, benchmark harness, and experiment409implementations. Every file carries the project's author header and the hfmarketdata.io data-source attribution.</p>410<ul class="tree">${sections}</ul>`;411  page(res, { title: "Code", active: "Code", body });412});413414app.get(/^\/file\/(.+)$/, (req, res) => {415  const rel = req.params[0];416  if (!C.isTextFile(rel)) return notFound(res);417  const raw = C.readText(rel);418  if (raw === null) return notFound(res);419  const name = rel.split("/").pop();420  const body = `<p class="crumb"><a href="/code">Code</a> / ${R.esc(rel)}</p>421<div class="card file-card"><div class="file-head"><span class="mono-small">${R.esc(rel)}</span>422<span class="mono-small">${raw.split("\n").length} lines</span></div>423<pre class="codeblock"><code class="hljs">${R.highlightFile(raw.slice(0, 400000), name)}</code></pre></div>`;424  page(res, { title: name, active: "Code", body });425});426427// ---------------------------------------------------------------- about428app.get("/about", (req, res) => {429  const body = `<h1 class="page-title">About this project</h1>430<div class="card md">431<p><strong>anomaly-atlas</strong> is an independent research project by432<strong>Simon-Pierre Boucher</strong> (<a href="mailto:contact@spboucher.ai">contact@spboucher.ai</a>) that asks:433given only open high-frequency market data from <a href="https://www.hfmarketdata.io">hfmarketdata.io</a>434(the sole data source), which statistical regularities — mean-reversion, lead-lag relationships,435calendar/seasonal effects — are <em>real</em>, and which are artifacts of bid-ask bounce, stale or436non-synchronized timestamps, survivorship, look-ahead, or microstructure noise?</p>437<p>The methodology is deliberately strict: pre-specified hypotheses and splits, artifact nulls that every438detector must beat, mandatory multiple-testing correction, a holdout touched exactly once, realistic439transaction-cost models, an append-only research log, hardware manifests embedded in every result, and no440result reported from an uncommitted tree. Detectors are validated on synthetic series first — a detector that441finds anomalies in a pure random walk is broken. The full methodology is codified in the442<a href="/doc/CLAUDE.md">research charter</a>.</p>443<h2>What counts as a real result</h2>444<ul>445<li>A regularity reaching Level 3: corrected, out-of-sample, robust, cost-real, confirmed on the once-touched holdout.</li>446<li>A rigorous artifact taxonomy for this dataset — letting others avoid mistaking artifacts for signals.</li>447<li>A clean demonstration that a widely-cited anomaly does NOT survive honest testing here (negative result).</li>448<li>A methodological contribution: a better artifact null or honest test for short-horizon effects on bar data.</li>449<li>A measured survival curve: what fraction of naively-significant effects remains after each layer of rigor.</li>450</ul>451<h2>What this is not</h2>452<p>Not a trading system, not trading advice, not a claim of arbitrage or "free money". The honest answer453"nothing survives" is an acceptable — and publishable — outcome. Do not assume Level-3 findings exist;454the research establishes the truth either way.</p>455<h2>Platform</h2>456<p>Everything runs on a consumer Apple Silicon Mac: DuckDB + parquet on the internal NVMe for out-of-core457columnar queries, NumPy/Accelerate for the math. This site is generated from the repository itself —458no hand-typed numbers.</p>459</div>`;460  page(res, { title: "About", active: "About", body });461});462463// ---------------------------------------------------------------- comments464function loadComments() {465  try {466    return JSON.parse(fs.readFileSync(COMMENTS_PATH, "utf8"));467  } catch {468    return [];469  }470}471472function saveComment(entry) {473  fs.mkdirSync(path.dirname(COMMENTS_PATH), { recursive: true });474  const all = loadComments();475  all.push(entry);476  fs.writeFileSync(COMMENTS_PATH, JSON.stringify(all, null, 2));477}478479const lastPostByIp = new Map(); // ip -> epoch ms (simple anti-flood)480481function commentsBody(flash) {482  const comments = loadComments().slice().reverse();483  const list = comments484    .map(485      (c) => `<article class="comment">486      <div class="comment-head"><strong>${R.esc(c.name)}</strong>487      <time class="tl-time">${R.esc((c.ts || "").slice(0, 16).replace("T", " "))} UTC</time>488      ${c.page ? `<span class="comment-page">on ${R.esc(c.page)}</span>` : ""}</div>489      <div class="comment-body">${R.esc(c.message)}</div></article>`490    )491    .join("");492  return `<h1 class="page-title">Comments</h1>493<p class="lede-small">Questions, methodological objections, artifact reports, pointers to literature —494all welcome. The most valuable comment here is "your effect is explained by X". Comments are public.495Nothing on this page (or this site) is investment advice.</p>496<section class="card">497  <h2>Leave a comment</h2>498  ${flash || ""}499  <form class="comment-form" method="POST" action="/comments">500    <div><label for="c-name">Name</label>501    <input type="text" id="c-name" name="name" maxlength="60" required placeholder="Your name or handle"></div>502    <div><label for="c-msg">Comment</label>503    <textarea id="c-msg" name="message" maxlength="2000" required placeholder="Be specific — cite the experiment or finding if possible."></textarea></div>504    <div><label for="c-page">Page it concerns (optional)</label>505    <input type="text" id="c-page" name="page" maxlength="120" placeholder="/experiments/expB_artifact_baselines"></div>506    <div class="hp"><label for="c-web">Website</label>507    <input type="text" id="c-web" name="website" tabindex="-1" autocomplete="off"></div>508    <button class="btn" type="submit">Post comment</button>509    <p class="form-note">Plain text only. One comment per 30 seconds. Abusive or promotional content is removed.</p>510  </form>511</section>512<div class="comment-list">${list || '<p class="lede-small">No comments yet — be the first.</p>'}</div>`;513}514515app.get("/comments", (req, res) => {516  let flash = "";517  if (req.query.ok) flash = `<p class="form-ok">Comment posted — thank you.</p>`;518  else if (req.query.err) flash = `<p class="form-error">${R.esc(String(req.query.err))}</p>`;519  page(res, { title: "Comments", active: "Comments", body: commentsBody(flash) });520});521522app.post("/comments", (req, res) => {523  const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress || "?";524  const now = Date.now();525  const err = (msg) => res.redirect(303, "/comments?err=" + encodeURIComponent(msg));526  if (now - (lastPostByIp.get(ip) || 0) < 30_000) return err("Please wait 30 seconds between comments.");527  const { name = "", message = "", page: pageRef = "", website = "" } = req.body || {};528  if (website.trim() !== "") return err("Submission rejected.");529  const cleanName = String(name).trim().slice(0, 60);530  const cleanMsg = String(message).trim().slice(0, 2000);531  const cleanPage = String(pageRef).trim().slice(0, 120);532  if (cleanName.length < 1) return err("Name is required.");533  if (cleanMsg.length < 3) return err("Comment is too short.");534  lastPostByIp.set(ip, now);535  saveComment({536    name: cleanName,537    message: cleanMsg,538    page: cleanPage || null,539    ts: new Date().toISOString(),540  });541  res.redirect(303, "/comments?ok=1");542});543544// ---------------------------------------------------------------- misc545app.get("/health", (req, res) => res.json({ ok: true, app: "anomaly-atlas-web", author: "Simon-Pierre Boucher", data_source: "hfmarketdata.io" }));546547function notFound(res) {548  res.status(404);549  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>` });550}551app.use((req, res) => notFound(res));552553app.listen(PORT, () => console.log(`anomaly-atlas-web listening on :${PORT}`));554