Evidence Observatory
Concept
A single live page — /observatory — that shows the vault knowing what it knows. Not a list of notes: an instrument panel. Four instruments, all rendered server-side from frontmatter, all clickable down to the underlying note:
1. The Claim Field — every tier-2 claim plotted on a confidence × evidence-class grid (speculative → high against 1-archaeology → 5-cognitive). The healthy corner (high confidence, class 1–2) glows; the dangerous corner (high confidence, class 3–5) is wired to flash. One glance answers: is our certainty backed by things that can be dated?
2. The Motif Constellation — shared motifs as glowing stars on a deep-time axis, positioned by earliest attestation, sized by occurrence count, colored by transmission verdict: descent green · contact blue · convergence purple · unresolved grey (the vault's existing .t-* palette). The constellation makes the master classification — the whole point of the methodology — visible as a night sky.
3. Source Diversity Spectra — per domain, a stacked bar of source evidence classes plus a verified-URL ratio and a counter-evidence health light (notes with empty or "none found (searched)" counter-evidence are surfaced, not hidden).
4. Open-Question Pressure Gauges — per target domain, a dial: open questions aimed at the domain vs. notes the domain has produced. High pressure = the register is re-tasking that domain. This is the three-tier loop (synthesis → gaps → gathering) rendered as physics.
Every dot, star, bar segment, and gauge needle is an <a> to its note or to the OPEN_QUESTIONS row anchor. Mission control, where every blinking light opens the file behind it.
Why it takes you back in time
The constellation's x-axis is time — ~100,000 BP (Qafzeh ochre) on the far left, the ethnographic present on the right, log-compressed so the Paleolithic doesn't crush the Bronze Age. Walking the observatory left to right is literally walking back out of deep time: first the lone archaeology-class stars (burials, ochre, temples), then the moment writing ignites a dense band at Sumer (~2600 BCE), then the great motif lineages — flood, dying god, sky father — streaking across traditions.
But the deeper time-travel is epistemic. The page doesn't just show what we believe about the past; it shows how far back our evidence actually reaches and where the light runs out. Claims resting on class 3–5 evidence sit visibly dimmer than dated ones. Undated motifs sit in a grey "before the light" margin rather than being silently dropped. The user experiences the methodology's central discipline — date or label — as a visual horizon: beyond this line, we are reconstructing, not observing. That is what an observatory is for: looking at very old light and being honest about its redshift.
Experience walkthrough
1. You click Observatory in the top nav (between Status and Motifs). The page opens on a near-black field — same --bg as the vault, slightly darker panel wells, like a control room at night.
2. The Motif Constellation dominates the top: a wide SVG sky. Three stars today — great-flood (blue, large halo: 11 occurrences), dying-rising-god, sky-father — each pulsing gently at its attestation date on the deep-time axis. Hovering freezes the pulse and raises a tooltip card: verdict, confidence, earliest attestation string verbatim, occurrence list. Clicking flies you to the motif note.
3. Below left, the Claim Field: a 4×5 grid of cells, claims as dots jittered within their cell (both axes are ordinal — this is a density grid, not a scatter). Cell high × 1-archaeology glows faint green. Any dot landing in high × 3-reconstruction or worse triggers a thin amber ring — calibration alarm. Today the field shows ~20 claims clustered in medium × 1/2, which is exactly what a young, honest vault should look like — and now you can see that.
4. Below right, Source Spectra: nine domain rows, each a stacked bar by evidence class with a small url_verified ratio chip and a pink tick for every claim whose counter_evidence is empty-equivalent. The adversarial reviewer's beat, automated into ambient light.
5. Across the bottom, nine pressure gauges. 04_indo_european and 05_abrahamic run hot (4 and 4 open questions each from the register); 03_egyptian idles. Each gauge lists its question IDs as tiny clickable chips (Q10, Q13, Q14, Q23…). A gatherer agent — or Óli — picks work straight off the hottest dial, which is precisely rule 3.6: gaps drive gathering.
6. The existing 3-second /api/version poll already reloads pages when the vault changes — so during a research wave the observatory updates as agents commit notes: new stars flare into the constellation, gauges swing as questions open and close. Leave it on a second monitor and watch the vault think.
Data from the vault (frontmatter parsing — be precise)
Everything needed already exists in frontmatter; nothing new is asked of researchers. Per instrument:
Claim Field — walk all .md under 01_–09_, keep type: claim (and type: tradition as hollow markers). Fields: confidence (ordinal: high | medium | low | speculative), evidence_class (1-archaeology | 2-text | 3-reconstruction | 4-ethnography | 5-cognitive), domain, status, title. Missing evidence_class → "unclassed" column, rendered, flagged.
Constellation — type: motif notes. Fields: transmission (the verdict → color), confidence (→ brightness/opacity), occurrences (→ halo radius = count of array items), attestation_earliest (→ x position), motif_id, title.
Spectra — type: source notes: evidence_class, url_verified (yes | no | not-online), tradition, domain. Plus per-domain counter_evidence health from claim/motif notes: empty, "", or none found (searched) (case-insensitive) → pink tick. type: synthesis notes contribute their free-text source_diversity and status (draft | reviewed | canon) as a caption row.
Gauges — parse 00_meta/OPEN_QUESTIONS.md table rows matching /^\| (Q\d+) \|/m; columns (split on |): question text, Target domain, Status (open | assigned | answered). The Q-backlog row is excluded from gauges but shown as a parked-pressure footnote with its count read from QUESTION_BACKLOG.md. Any type: question notes found in domains merge in via target_domain/status/answered_by.
Three parsing gotchas (verified against live notes — these are load-bearing):
1. Block-style YAML lists are invisible to the current parser. parseFrontmatter in tools/server.ts matches only ^(\w[\w_]):\s(.)$ per line. Real notes use both* styles: great-flood.md has inline occurrences: [sumerian, babylonian-akkadian, …], but claim-qafzeh-ochre-earliest-symbolic-behavior.md has block-style sources: followed by - "…" lines, which the current regex drops entirely (value parses as empty). The aggregator must extend the parser: when a key's value is empty and following lines match /^\s+-\s+/, collect them as the array. Inline arrays: strip [ ], split on , outside quotes.
2. Inline comments after values are real and already handled — keep the existing .replace(/\s+#.*$/, "") (e.g. transmission: contact # verdict scoped to… in great-flood.md). Do not strip # inside quoted strings.
3. Dates are prose, not numbers. attestation_earliest values look like "c. 1635 BCE, Old Babylonian Atra-ḫasīs tablets … (2-text)", "c. 92,000 BP — …", "8th c. CE". Normalize with ordered regexes: (\d[\d,])\s(?:ka|kya) → ×1000 BP; (\d[\d,])\sBP → BP; (\d[\d,])\sBCE?\b → +1950; (\d+)(?:st|nd|rd|th)\sc\.?\s(BCE?|CE|AD) → century midpoint; (\d[\d,])\s(?:CE|AD) → 1950−n. Take the earliest parseable date in the string (motifs list allusion + attestation). No match → the grey "undated" margin, never dropped. Embedded evidence class for motifs (no evidence_class field): extract /\b([1-5])-(archaeology|text|reconstruction|ethnography|cognitive)\b/ from the same string.
Current corpus (2026-06-11): 71 typed notes — ~30 sources, ~25 claims, 3 motifs, 3+ tradition profiles, 1 synthesis — 26 register questions + 18 backlog. Small enough to verify the aggregator's output by hand against the files; that hand-check is the acceptance test.
Implementation sketch
Bun only, zero npm deps, all inside the existing tools/server.ts (read-only stance unchanged):
GET /api/observatory— server-side aggregation route. Reuses the directory-walk pattern fromvaultVersion()/countFiles(); parses every domain.mdonce with the extendedparseFrontmatter(block-list support added — also benignly improves the existing note renderer's facts panel); parses OPEN_QUESTIONS.md rows. Returns one JSON payload:{ claims: [{href, title, confidence, evidence_class, domain, status, counter_ok}], motifs: [{href, title, transmission, confidence, year_bp, undated, occurrences, attestation_raw}], sources_by_domain, questions: [{id, target, status, anchor}], generated}. Cache keyed onvaultVersion()(the existing 1 s-TTL mtime scan), so it recomputes only when the vault changes.GET /observatory— new page through the existingpage()chrome (nav, progress bar, footer, CSS vars). Body is a placeholder shell plus one inline<script>(vanilla, ~250 lines) that fetches/api/observatoryand builds four<svg>elements viadocument.createElementNS. No charting library: the constellation is<circle>s with an SVG radial-gradient glow filter (feGaussianBlur+feMerge), log-scaledcx = f(year_bp); the claim grid is<rect>cells + jittered<circle>s with deterministic jitter (hash of href, so dots don't move between reloads); spectra are<rect>stacks; gauges are<path>arcs with a needle<line>. Every glyph wrapped in<a href>; native<title>children give free tooltips, one positioneddivupgrade for the rich motif card.- Nav: add
["/observatory", "Observatory"]to thelinksarray innav(). - Live: nothing new — the injected
/api/versionpoll inpage()already reloads on vault change. - Style: reuse
--green/--blue/--purple/--dimand badge classes so the observatory's verdict colors are pixel-identical to the badges on every note page. - Tests: a small
tools/observatory.test.ts(bun test) pinning the three gotchas — block-list parsing, date normalization on the exact live strings quoted above, and question-row extraction — so future note formats fail loudly.
Estimated diff: ~120 lines server-side (parser + route), ~250 lines page script/SVG, ~10 lines CSS additions. No new files except the test.
Images needed (numbered GPT-5.5 prompts)
All via codex CLI per AGENTS.md §5; no text in images, no recognizable living people. Targets in assets/illustrations/.
1. evidence-observatory.png (idea-note banner & page hero) — "Photorealistic cinematic wide shot, interior of a remote mountaintop astronomical observatory at night: a lone astronomer's silhouette before a vast curved window, but instead of stars the sky outside is a faint constellation of glowing points in green, blue, and violet over a dark river valley dotted with distant Bronze Age fire-lit ziggurats and Paleolithic cave mouths along a timeline of terrain receding to the horizon; cold indoor instrument-glow in the foreground, warm ancient firelight in the deep distance; volumetric haze, anamorphic lens, no text, no writing, archaeologically grounded architecture."
2. observatory-constellation.png (section banner for the constellation) — "Photorealistic night sky long-exposure over a layered archaeological landscape receding into distance: nearest, an excavated Sumerian temple platform lit by dim work lamps; further, the dark mass of Göbekli Tepe's T-pillars; furthest, a torch-lit cave entrance in a cliff face; above, stars subtly tinted green, blue, and violet with soft halos, a faint band like a timeline of light crossing the sky; cinematic, archaeologically accurate, no text, no people's faces."
3. observatory-claim-field.png (optional section banner) — "Photorealistic macro shot of an antique brass-and-glass scientific instrument panel in a dark room: a grid of small round indicator lamps, most glowing calm amber and green, one corner lamp glowing warning-amber; shallow depth of field, dust motes in a single beam of light, early-20th-century observatory control room aesthetic, no text, no labels, no digits."
Effort (S/M/L + what ships first)
Overall: M. The server work is small because the page chrome, CSS system, walk pattern, and live-reload already exist; the real cost is the date normalizer and SVG polish.
Shipping order:
1. S — ships first: extended parseFrontmatter (block lists) + /api/observatory JSON route + observatory.test.ts. Pure data, verifiable against the 71 notes by hand. Useful to agents immediately even with no UI (the bias reviewer can curl it).
2. S: Claim Field + Pressure Gauges page at /observatory with nav link — grid and arcs are trivial SVG; this alone already answers "where is the vault miscalibrated and who has homework."
3. M: Motif Constellation — date normalizer, log time axis, glow filters, motif tooltip card. The centerpiece; worth the polish pass.
4. S: Source Diversity Spectra + counter-evidence health ticks.
5. S: Images 1–3 and INDEX.md link (implemented experiences must be linked from INDEX or they don't exist).