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%
6.7 KB · 220 lines javascript
Raw Blame History
1// ============================================================================2//  Project   : anomaly-atlas3//  File      : web/lib/content.js4//  Purpose   : Content index over the synced research-repo snapshot (content/)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 path = require("path");17const matter = require("gray-matter");1819const CONTENT_ROOT = path.join(__dirname, "..", "content");2021const TEXT_EXT = new Set([22  ".md", ".py", ".sh", ".toml", ".yaml", ".yml", ".cff", ".json",23  ".js", ".css", ".sql", ".txt", ".log",24]);2526/** Resolve a repo-relative path safely inside content/, or return null. */27function safeResolve(rel) {28  const abs = path.resolve(CONTENT_ROOT, rel);29  if (!abs.startsWith(CONTENT_ROOT + path.sep) && abs !== CONTENT_ROOT) return null;30  return abs;31}3233function exists(rel) {34  const abs = safeResolve(rel);35  return abs !== null && fs.existsSync(abs);36}3738function readText(rel) {39  const abs = safeResolve(rel);40  if (!abs || !fs.existsSync(abs) || !fs.statSync(abs).isFile()) return null;41  return fs.readFileSync(abs, "utf8");42}4344/** Read a markdown file, returning { data (front matter), content }. */45function readMarkdown(rel) {46  const raw = readText(rel);47  if (raw === null) return null;48  try {49    return matter(raw);50  } catch {51    return { data: {}, content: raw };52  }53}5455/** List a directory inside content/: [{name, rel, dir, size}] */56function listDir(rel) {57  const abs = safeResolve(rel || ".");58  if (!abs || !fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) return null;59  return fs60    .readdirSync(abs)61    .filter((n) => !n.startsWith(".") && n !== "node_modules")62    .map((n) => {63      const st = fs.statSync(path.join(abs, n));64      return {65        name: n,66        rel: path.posix.join(rel || "", n),67        dir: st.isDirectory(),68        size: st.size,69      };70    })71    .sort((a, b) => (a.dir !== b.dir ? (a.dir ? -1 : 1) : a.name.localeCompare(b.name)));72}7374/** Recursively collect files under rel matching a predicate. */75function walk(rel, predicate, out = []) {76  const entries = listDir(rel);77  if (!entries) return out;78  for (const e of entries) {79    if (e.dir) walk(e.rel, predicate, out);80    else if (predicate(e)) out.push(e);81  }82  return out;83}8485function isTextFile(rel) {86  return TEXT_EXT.has(path.extname(rel).toLowerCase()) || path.basename(rel) === "Makefile";87}8889/** Parse research/LOG.md into entries [{title, body}] (## headings). */90function parseLogEntries() {91  const md = readMarkdown("research/LOG.md");92  if (!md) return [];93  const parts = md.content.split(/^## /m).slice(1);94  return parts.map((p) => {95    const nl = p.indexOf("\n");96    return { title: p.slice(0, nl).trim(), body: p.slice(nl + 1).replace(/^---\s*$/m, "").trim() };97  });98}99100/** Experiment cards: micro experiments + candidates. */101function listExperiments() {102  const out = [];103  for (const base of ["experiments/micro", "experiments"]) {104    const entries = listDir(base) || [];105    for (const e of entries) {106      if (!e.dir || e.name === "micro") continue;107      const readme = readMarkdown(path.posix.join(e.rel, "README.md"));108      const hasAnalysis = (readText(path.posix.join(e.rel, "analysis.md")) || "").length > 400;109      const runs = listResultRuns().filter((r) => r.experiment === e.name);110      let purpose = "";111      if (readme) {112        const line = readme.content.split("\n").find((l) => l.trim() && !l.startsWith("#"));113        purpose = line ? line.trim() : "";114      }115      out.push({116        id: e.name,117        rel: e.rel,118        purpose,119        status: runs.length > 0 && hasAnalysis ? "completed" : runs.length > 0 ? "has results" : "scaffolded",120        runs: runs.length,121      });122    }123  }124  return out;125}126127/** Result runs: results/<experiment>/<timestamp>/*.json */128function listResultRuns() {129  const out = [];130  for (const exp of listDir("results") || []) {131    if (!exp.dir) continue;132    for (const run of listDir(exp.rel) || []) {133      if (!run.dir) continue;134      const files = (listDir(run.rel) || []).filter((f) => !f.dir);135      out.push({ experiment: exp.name, timestamp: run.name, rel: run.rel, files });136    }137  }138  return out.sort((a, b) => b.timestamp.localeCompare(a.timestamp));139}140141/** Atlas findings: atlas/<anomaly_id>/<version>/finding.json (+ confidence.md). */142function listFindings() {143  const out = [];144  for (const anomaly of listDir("atlas") || []) {145    if (!anomaly.dir) continue;146    for (const ver of listDir(anomaly.rel) || []) {147      if (!ver.dir) continue;148      const finding = readJson(path.posix.join(ver.rel, "finding.json"));149      if (!finding) continue;150      out.push({151        id: anomaly.name,152        version: ver.name,153        rel: ver.rel,154        level: finding.confidence_level ?? 0,155        title: finding.title || anomaly.name,156        summary: finding.summary || "",157        negative: !!finding.negative_result,158        finding,159      });160    }161  }162  return out.sort((a, b) => b.level - a.level || a.id.localeCompare(b.id));163}164165function readJson(rel) {166  const raw = readText(rel);167  if (raw === null) return null;168  try {169    return JSON.parse(raw);170  } catch {171    return null;172  }173}174175/** Build info written by sync-content.sh (commit, counts, date). */176function buildInfo() {177  return readJson("build-info.json") || {};178}179180/** Site-wide stats for the home page. */181function stats() {182  const bib = readText("research/bibliography.md") || "";183  const sources = bib.split("\n").filter((l) => l.trim().startsWith("- ")).length;184  const gapsDoc = readText("research/research_gaps.md") || "";185  const gaps = (gapsDoc.match(/^#{2,3}\s+H\d{2}/gm) || []).length;186  const experiments = listExperiments();187  const notes = (listDir("research/notes") || []).filter((f) => f.name.endsWith(".md") && f.name !== "README.md").length;188  const findings = listFindings();189  return {190    sources,191    gaps,192    notes,193    experiments: experiments.length,194    experimentsDone: experiments.filter((e) => e.status === "completed").length,195    resultRuns: listResultRuns().length,196    logEntries: parseLogEntries().length,197    findings: findings.length,198    negatives: findings.filter((f) => f.negative).length,199    build: buildInfo(),200  };201}202203module.exports = {204  CONTENT_ROOT,205  safeResolve,206  exists,207  readText,208  readMarkdown,209  readJson,210  listDir,211  walk,212  isTextFile,213  parseLogEntries,214  listExperiments,215  listResultRuns,216  listFindings,217  buildInfo,218  stats,219};220