Add optional science toolbelt probe

This commit is contained in:
Brandon Schneider 2026-05-12 00:21:34 -05:00
parent 8b62423d6b
commit 4f2272fb31
6 changed files with 385 additions and 1 deletions

1
.gitignore vendored
View file

@ -38,6 +38,7 @@ scripts/venv_unsloth/
**/venv_wgpu/
**/*.venv/
**/venv/
.venv-science/
# API Keys and credentials (NEVER track in git)
API KEYS/

View file

@ -0,0 +1,79 @@
# Optional Science Toolbelt
These tools are optional reference surfaces for math-first work. They are not
default repo dependencies. Add them to a local environment only when a task
needs an executable witness, conversion adapter, or independent solver.
The operating rule is simple: Lean remains the source of truth; these tools
produce receipts, counterexamples, fixtures, and sanity checks.
## Install Manifests
Python packages that are reasonable to install into a task-specific virtual
environment:
```bash
uv venv .venv-science
source .venv-science/bin/activate
uv pip install -r requirements-optional-science.txt
```
Equivalent npm convenience commands:
```bash
npm run setup-science-light
npm run probe-science
```
Native command-line tools are listed in:
```text
system-packages-optional-science.txt
```
Do not wire these into default CI unless the workflow is explicitly optional or
the tool is already installed on the runner.
## Probe What Is Available
Use the probe before asking an agent to rely on a domain tool:
```bash
python3 scripts/probe_science_toolbelt.py
python3 scripts/probe_science_toolbelt.py --json
python3 scripts/probe_science_toolbelt.py --json --out shared-data/artifacts/science_toolbelt/probe.json
```
The probe exits successfully even when optional tools are missing. Missing tools
are data, not failure.
## Domain Priorities
| Domain | First tools | Use in this stack |
| --- | --- | --- |
| Genetics / bioinformatics | Biopython, pysam, samtools, bcftools, minimap2 | Validate FASTA/FASTQ/GenBank/SAM/BAM/VCF fixtures for the genetic-code, Hachimoji, and PIST surfaces. |
| CFD / PDE | Dedalus, ParaView | Produce spectral PDE reference traces for Burgers/KdV/hyperfluid claims without committing to a heavyweight engineering CFD stack. |
| Cryptography | liboqs-python, PyCryptodome, galois | Check post-quantum KEM/signature examples, hashes, finite-field arithmetic, and receipt digests. |
| Chemistry / materials | RDKit, Open Babel | Parse/canonicalize SMILES, compute descriptors, and turn molecular claims into inspectable fixtures. |
| Formal bridge | Z3, cvc5 | Search bounded counterexamples before spending Lean effort. |
| Algebra / graph theory | SageMath, GAP, NetworkX, Graphviz | Generate lattice/group/graph witnesses and diagrams for later Lean or receipt promotion. |
| Compression / signal | zstandard, PyWavelets | Provide compression baselines and spectral/wavelet witnesses for signal-shaping claims. |
## What Not To Do
- Do not add these packages to the default repo environment.
- Do not treat a solver result as a theorem.
- Do not commit generated datasets unless they are promoted as small,
receipt-bearing evidence.
- Do not copy implementation code from external tools into the repo.
## Receipt Pattern
For any adapter built on this toolbelt, prefer:
1. Input fixture path.
2. Tool name and version from `probe_science_toolbelt.py`.
3. Exact command or Python module call.
4. Output hash and short human-readable summary.
5. Link to the Lean theorem, claim registry entry, or distilled doc that the
receipt supports.

View file

@ -5,7 +5,9 @@
"scripts": {
"install-python": "uv python install 3.11.15",
"setup-cad-env": "cd 5-Applications/text-to-cad && python3.11 -m venv .venv && ./.venv/bin/pip install -r requirements-cad.txt",
"verify-cad": "cd 5-Applications/text-to-cad && ./.venv/bin/python -c \"import build123d; import OCP; print('CAD dependencies OK')\""
"verify-cad": "cd 5-Applications/text-to-cad && ./.venv/bin/python -c \"import build123d; import OCP; print('CAD dependencies OK')\"",
"setup-science-light": "uv venv .venv-science && . .venv-science/bin/activate && uv pip install -r requirements-optional-science.txt",
"probe-science": "python3 scripts/probe_science_toolbelt.py"
},
"dependencies": {
"better-sqlite3": "^12.4.1"

View file

@ -0,0 +1,34 @@
# Optional science toolbelt for receipt-producing adapters.
#
# Install only when a task needs these domains:
#
# uv pip install -r requirements-optional-science.txt
#
# These packages are intentionally not part of the default repo setup. They
# provide reference implementations and data-format adapters for math-first
# verification receipts.
# Genetics / bioinformatics
biopython>=1.87
pysam>=0.24.0
# Chemistry / materials
rdkit>=2026.3.1
# SMT / formal-methods bridge
z3-solver>=4.16.0.0
cvc5>=1.3.4
# Cryptography / finite fields / symbolic checks
pycryptodome>=3.23.0
galois>=0.4.6
# Graphs, signal analysis, and compression baselines
networkx>=3.5
PyWavelets>=1.9.0
zstandard>=0.25.0
# Heavy or native-stack options. Keep commented unless a task explicitly needs
# the solver and the host has the native prerequisites.
# dedalus>=3.0.5
# liboqs-python>=0.14.1

242
scripts/probe_science_toolbelt.py Executable file
View file

@ -0,0 +1,242 @@
#!/usr/bin/env python3
"""Probe optional science tools without requiring them.
The goal is not to make these tools part of the default stack. The goal is to
let agents and CI-adjacent smoke checks discover which reference solvers,
format adapters, and verification backends are available on the current host.
Exit code:
0 probe completed; missing optional tools are reported in the payload.
2 invalid CLI arguments or unable to write output.
"""
from __future__ import annotations
import argparse
import importlib
import json
import shutil
import subprocess
import sys
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any
@dataclass(frozen=True)
class PythonTool:
key: str
domain: str
module: str
purpose: str
@dataclass(frozen=True)
class CommandTool:
key: str
domain: str
command: str
purpose: str
version_args: tuple[str, ...] = ("--version",)
PYTHON_TOOLS: tuple[PythonTool, ...] = (
PythonTool(
"biopython",
"genetics",
"Bio",
"FASTA/FASTQ/GenBank parsing and sequence manipulation",
),
PythonTool("pysam", "genetics", "pysam", "SAM/BAM/CRAM/VCF access from Python"),
PythonTool(
"rdkit",
"chemistry",
"rdkit",
"SMILES parsing, canonicalization, descriptors, fingerprints",
),
PythonTool("z3-solver", "formal-methods", "z3", "SMT checks before Lean proof work"),
PythonTool("cvc5", "formal-methods", "cvc5", "SMT checks and model finding"),
PythonTool(
"pycryptodome",
"cryptography",
"Crypto",
"hash/signature/cipher reference primitives",
),
PythonTool("galois", "cryptography", "galois", "finite-field arithmetic"),
PythonTool(
"networkx",
"graph-theory",
"networkx",
"graph certificates and topology receipts",
),
PythonTool(
"pywavelets",
"signal-processing",
"pywt",
"wavelet decompositions for spectral receipts",
),
PythonTool(
"zstandard",
"compression",
"zstandard",
"zstd baseline and dictionary-training adapter",
),
PythonTool("dedalus", "cfd-pde", "dedalus", "spectral PDE reference solver"),
PythonTool(
"liboqs-python",
"cryptography",
"oqs",
"Open Quantum Safe KEM/signature reference adapter",
),
)
COMMAND_TOOLS: tuple[CommandTool, ...] = (
CommandTool(
"samtools",
"genetics",
"samtools",
"SAM/BAM/CRAM command-line verification",
),
CommandTool("bcftools", "genetics", "bcftools", "VCF/BCF command-line verification"),
CommandTool("minimap2", "genetics", "minimap2", "sequence alignment smoke checks"),
CommandTool(
"sage",
"algebra-crypto",
"sage",
"lattice, group, and symbolic mathematics",
("--version",),
),
CommandTool("gap", "algebra", "gap", "computational group-theory checks", ("--version",)),
CommandTool("z3", "formal-methods", "z3", "SMT solver CLI", ("--version",)),
CommandTool("cvc5", "formal-methods", "cvc5", "SMT solver CLI", ("--version",)),
CommandTool("zstd", "compression", "zstd", "compression baseline CLI", ("--version",)),
CommandTool("dot", "graph-theory", "dot", "Graphviz graph rendering for witness diagrams", ("-V",)),
CommandTool("obabel", "chemistry", "obabel", "Open Babel format conversion", ("-V",)),
CommandTool("paraview", "cfd-pde", "paraview", "CFD/PDE visualization frontend", ("--version",)),
)
def _module_version(module: Any) -> str | None:
for attr in ("__version__", "VERSION", "version"):
value = getattr(module, attr, None)
if value is None:
continue
if callable(value):
try:
value = value()
except Exception:
continue
return str(value)
return None
def _probe_python(tool: PythonTool) -> dict[str, Any]:
try:
module = importlib.import_module(tool.module)
except Exception as exc:
return {
**asdict(tool),
"available": False,
"error": f"{type(exc).__name__}: {exc}",
}
return {
**asdict(tool),
"available": True,
"version": _module_version(module),
"path": getattr(module, "__file__", None),
}
def _run_version(path: str, args: tuple[str, ...]) -> str | None:
try:
result = subprocess.run(
[path, *args],
capture_output=True,
text=True,
timeout=5,
check=False,
)
except Exception:
return None
text = (result.stdout or result.stderr).strip()
if not text:
return None
return text.splitlines()[0]
def _probe_command(tool: CommandTool) -> dict[str, Any]:
path = shutil.which(tool.command)
if path is None:
return {
**asdict(tool),
"available": False,
}
return {
**asdict(tool),
"available": True,
"path": path,
"version": _run_version(path, tool.version_args),
}
def build_report() -> dict[str, Any]:
python_results = [_probe_python(tool) for tool in PYTHON_TOOLS]
command_results = [_probe_command(tool) for tool in COMMAND_TOOLS]
available = sum(1 for item in python_results + command_results if item["available"])
total = len(python_results) + len(command_results)
by_domain: dict[str, dict[str, int]] = {}
for item in python_results + command_results:
bucket = by_domain.setdefault(item["domain"], {"available": 0, "total": 0})
bucket["total"] += 1
if item["available"]:
bucket["available"] += 1
return {
"schema": "research_stack_optional_science_toolbelt_probe_v1",
"summary": {
"available": available,
"total": total,
"by_domain": by_domain,
},
"python": python_results,
"commands": command_results,
}
def _print_text(report: dict[str, Any]) -> None:
summary = report["summary"]
print(f"optional science toolbelt: {summary['available']}/{summary['total']} available")
for section in ("python", "commands"):
print(f"\n{section}:")
for item in report[section]:
mark = "OK" if item["available"] else "--"
version = item.get("version")
suffix = f" ({version})" if version else ""
print(f" {mark} {item['key']}: {item['purpose']}{suffix}")
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--json", action="store_true", help="emit JSON instead of text")
parser.add_argument("--out", type=Path, help="write the JSON report to this path")
args = parser.parse_args(argv)
report = build_report()
if args.out:
try:
args.out.parent.mkdir(parents=True, exist_ok=True)
args.out.write_text(
json.dumps(report, indent=2, sort_keys=True) + "\n",
encoding="utf-8",
)
except OSError as exc:
print(f"error: failed to write {args.out}: {exc}", file=sys.stderr)
return 2
if args.json:
print(json.dumps(report, indent=2, sort_keys=True))
else:
_print_text(report)
return 0
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -0,0 +1,26 @@
# Optional system packages for science toolbelt adapters.
#
# These are command-line tools or heavyweight native stacks that Python
# requirements cannot reliably install. Names are Debian/Ubuntu-style package
# names where available; distro packages vary.
# Genetics / bioinformatics
samtools
bcftools
minimap2
# Formal methods / algebra
cvc5
z3
gap
sagemath
# Compression and receipt payload baselines
zstd
# Visualization / data inspection
graphviz
paraview
# Chemistry / materials native helpers
openbabel