teal-sea / zeta-labstate of record · compiled 14 Aug 2026 · revision 9ebdea0 · source

Library · AGENTS.md

AGENTS.md — operating context for the repo root

5,045 words · 564 lines · source

A computational laboratory for the Riemann zeta function and RH. Read README.md for the front door and docs/00-orientation.md for scope.

ROADMAP.md carries the project's decisions, deliberate non-goals, known gaps and the next planned build — read it before proposing or planning work.

This file is the single source of operating context for any coding agent working in this repository (Claude Code, Codex, Cursor, Aider, …). CLAUDE.md is a pointer to this file; do not duplicate content between them.

Setup (first run in a fresh clone)

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/pip install -e .
.venv/bin/python -m pytest -q -m "not slow"   # confirm green before changing anything

Check the ball-arithmetic backend before you trust a green run:

.venv/bin/python -c "from zeta import rigor; print(rigor.BACKEND, rigor.available_backends())"
# want: python-flint ['mpmath.iv', 'python-flint']

If python-flint is missing, rigor.py silently falls back to mpmath's iv context. That is by design and the fallback is correct — but it is roughly 1600× slower on the certified paths (one test_rigor.py case goes from 0.76 s to over twenty minutes, which reads as a hung fast tier, not a slow one), and the five skipif(not HAVE_FLINT) tests silently disappear. Three of those say "needs both backends installed": they are the Arb-vs-mpmath cross-check that is the whole reason rigor.py may claim the word certified. A suite that reports "5 skipped" here is not exercising that cross-check, so a fresh clone should install python-flint (it is pinned in requirements.txt) rather than treat the skips as normal.

The knowledge index

CONTEXT.md is a generated index of the public API, the document list, the script list and test counts — the facts. This file carries the judgment. Regenerate the facts rather than editing them:

.venv/bin/python scripts/make_context.py          # rewrite CONTEXT.md
.venv/bin/python scripts/make_context.py --check  # non-zero exit if stale
.venv/bin/python scripts/make_context.py --flat   # + CONTEXT_FLAT.md, whole repo in one file

Regenerate it whenever you add or rename a public function, a doc or a script. llms.txt is the short curated map for tools that look for one.

Multiple agents / parallel sessions

Several agents or sessions may work this repository in parallel, on branches or worktrees. To prevent scope creep and collisions:

Outside environments (read-only mounts, notebook agents)

Some sessions run this laboratory from an environment that is not this checkout: a notebook-style agent (Claude Science and anything like it) that mounts the repository read-only and brings its own Python. That suits the exploratory half of this tree — cells, background execution and interruption fit expensive mpmath work — but it breaks two assumptions the rest of this file is entitled to make, and both break silently.

Run the preflight as the first cell, before any mathematics:

python scripts/science_preflight.py          # or --allow-fallback

It reports the interpreter and dependency set, plus three things no outside session can infer from a snapshot: whether rigor.BACKEND is really Arb (a missing python-flint degrades to mpmath's iv — correct, ~1600× slower, and it removes the cross-check that is the only reason rigor.py may use the reserved word), whether a Lean build is possible at all, and the next free docs/ number. It exits non-zero when the environment cannot support the claims this tree knows how to make.

The standing rules for such a session:

Where the operating material lives

This repository is the public research record: mathematics, tests, proofs, evidence, and enough method that an outside reader can evaluate or reproduce a claim. That is why it is public, and it is the standard for what belongs here.

How the laboratory is operated lives in a separate private repository: operator strategy, hunt briefs and their generation, the prompt corpus, session launching, telemetry economics, and any future routing or allocation logic. Those have no bearing on whether a scientific claim here is correct, so they are not published.

The boundary, applied with judgment rather than by a rule engine:

If an outside observer needs it to evaluate or reproduce a public claim, it belongs here. If it teaches the lab how to allocate, route, prompt, or operate itself, it belongs there unless reproducibility needs it.

Preregistrations and protocols stay here even when unflattering — the harness gate record (harness/VERDICT.md, harness/gate-evidence/) is public precisely because a negative result about our own tooling is credibility, not capability.

A private operating repository does not make the research process private: this tree stays unusually open about criticism, corrections and claims that did not survive. Ownership and visibility are separate questions from transparency, and only the last one is a promise this repository makes.

The shape, so a session launched into this tree knows which side it is on: teal-sea is the parent, the operating repository directs pursuits, and this repository is a pursuit. The research is yours to do and commit here. Two things are not: if you find an infrastructure idea, do not reach across and edit the operating repository, report it as a Core candidate. If you find an interesting loose end outside your mission, do not pursue it, report it as a thread. Zeta is a worker target, not the operator's console, and it must not grow into an operating database.

Flag genuinely ambiguous cases to the operator. Do not build a framework to adjudicate them.

How the work is organised

Two working ideas and one objective. None is settled; all three are here rather than in a strategy document because you should meet them while working.

Core ↔ Pursuits. Core is work that improves the lab's reusable ability to work: infrastructure, tooling, telemetry, agent coordination, reusable method. Pursuits are what the lab is chasing outward: research questions, hunts, investigations. They are not a hierarchy and not an ancestry — they create each other in both directions. A hunt that needs a tool produces Core; Core work that trips over a phenomenon produces a Pursuit; a piece of Core can itself become the subject of a Pursuit (harness/ did exactly that, and lost). The distinction describes a thing's current role, not its rank or its origin. Do not rename directories to make the tree look like the metaphor.

Forage, don't roadmap. Explore several directions cheaply; when one produces credible signal, feed it more; when it stops, stop feeding it. Preserve the threads you are not pulling, so choosing one direction does not require forgetting the others — observations become issues, leads go to the roster with the operator. This is a working strategy, not a proven optimal policy.

The economic objective: maximize valuable output per monetary unit of input. This is not "minimize tokens". Money is the input and valuable output is the objective; models, tokens, extra agents, verification, formalization, infrastructure and operator time are all allocation choices. A more expensive approach is the right one whenever the extra output justifies the cost — and a cheap approach that yields low-value or unreliable output is not efficient, it is just cheap. We do not yet have a complete metric for "valuable output". Do not invent one and treat it as settled; it is an open research question, not a KPI.

Design discipline, learned the expensive way. Before adding any abstraction, answer: what live thing in this repository will use this immediately? If the answer is "future agents might", do not build it. Prefer real need → smallest implementation → actual use → measurement → only then generalization. Do not build infrastructure without a live consumer, do not generalize a workflow before the concrete workflow earns it, and do not build a meta-system to manage the meta-system. harness/VERDICT.md is what the alternative cost.

Read that verdict as a bet properly made and properly ended, not as a blunder. It was a reasonable thing to try, it was built well, it was tested against the practice it meant to improve, and it lost. Being able to kill something you funded, on evidence, is the habit worth keeping — a lab that cannot do that has preferences rather than a method. Retiring it is a success of the process and a failure of the thing, and the two are not the same judgement.

Observations, and the work roster

Two different things that were once one file, split by what kind of statement they are rather than by where they lived.

An observation is public. Something measured, noticed, broken or bounded is a fact about the subject or about this tree, and it is true whether or not anyone pursues it. Those go in the open, as a GitHub issue on this repository, or as a doc and a test when they are big enough to deserve one. Issue #21 is a measured result about which properties of ζ discriminate; issue #22 is a scope caveat that bounds every claim compiler/ makes; issue #20 is a defect. All three are checkable by a stranger, which is the point.

A lead is private. That we intend to chase something, in what order, with what budget, lives in the operator's roster. A backlog announces what the lab is about to work on, which is allocation, and allocation is operating material.

The line: an issue says "this is true and unresolved." The roster says "this one is next."

If you notice something and are not chasing it now, open an issue — do not start a backlog file here. Record the observation; leave the priority to the roster.

scripts/70_lab_state.py still derives live work from git — every branch ahead of origin/main, right by construction, needing nobody to maintain it.

Hard rules

A result is not downgraded to nothing because its novelty is unsearched. A kernel-checked statement this lab produced is an original kernel-checked result, full stop, and the front of the house should say so. The certainty ladder below still governs how strongly it may be phrased; the ladder grades confidence, it does not decide authorship. Refutations count as output too — a route closed with a witness is a result, not an absence of one.

Layout

The naming trap: three different "theta"s

  1. zeta.core.theta — Jacobi θ(x) = Σ_{n∈ℤ} e^{−πn²x} (the heat kernel; modular identity θ(1/x) = √x·θ(x)).
  2. zeta.core.rs_theta — Riemann–Siegel phase ϑ(t) in Z(t) = e^{iϑ(t)}ζ(½+it) (zeta.statistics.riemann_siegel_theta is the fast vectorized variant).
  3. zeta.explicit.theta_cheb — Chebyshev's prime sum θ(x) = Σ_{p≤x} log p.

Related trap: xi(s) is the completed zeta (entire, ξ(s) = ξ(1−s)); Xi(t) = xi(1/2 + it) is real for real t. Do not use Ξ for the function of s. In heatflow.py, H₀(z) = (1/8)·Ξ(z/2) — mind the factor 8 and the z/2.

And a fourth collision, this one in the import system: zeta.explicit.li is the logarithmic integral and is re-exported as zeta.li, but zeta/li.py is Li's criterion, so after any import zeta.li the package attribute is the module and zeta.li(x) raises TypeError. Documented in zeta/li.py and pinned by tests/test_li.py. Write zeta.explicit.li for the function and from zeta.li import … for the module; never from zeta import li. The Jensen coefficients also come in two normalisations: zeta/li.py uses GORZ's 8·ξ(½+z) = Σ γ(n) z^{2n}/n!, docs/12 §8.1 derives the heat-kernel one; they differ by 64·4ⁿ, which changes no hyperbolicity and no Turán ratio.

Cached data

Expensive results cache to data/ (.json zero tables are committed; .npz scans are gitignored and regenerate on first use). Cache keys encode parameters in filenames. If you change numerical internals, delete the affected cache files and re-run, or stale numbers will "pass".

How to run things

cd <repo root>
.venv/bin/python -m pytest -q                 # full suite (2189 tests, ~10-20 min)
.venv/bin/python -m pytest -q -m "not slow"   # fast tier (2122 tests, ~3-8 min)
.venv/bin/python scripts/06_tour.py           # end-to-end sanity + demo
.venv/bin/python scripts/make_figures.py --quick   # all figures into figures/
cd lean && PATH="$HOME/.elan/bin:$PATH" lake build  # the certified arm (0 sorrys)

Tests run in parallel by default (-n auto, set in pyproject.toml) — the fast tier goes from ~320 s to ~115 s. Add -n0 when you need --pdb or clean per-test output — not -p no:xdist, which unloads the plugin that owns the -n auto already in addopts and dies with "unrecognized arguments: -n". Before optimising anything, run --durations=20: the cost concentrates in test_li.py, test_heatflow.py and test_weil.py (high-precision zero sums and quadrature).

Tests use mpmath's zetazero / siegelz / grampoint / nzeros as an independent oracle against the hand-rolled machinery — preserve that pattern when adding features: implement the mathematics, then cross-check.

Ground truth for quick assertions