Research-Stack/scripts/math-first/require_math_evidence.py
Devin AI 0c9efac330 chore(consolidation): integrate E8Sidon stack (PRs #79 #80 #81 #89) into one PR
Squash the four overlapping feature branches into a single change set against
main, eliminating cross-PR merge conflicts and the duplicated CI-fix scripts.

What this brings in (merge order #79 -> #80 -> #81 -> #89):
- #79 refactor(infra): shared utilities (4-Infrastructure/lib/*: q16, hashing,
  jsonl, fraction_utils) + the scripts/math-first/* validators that the
  math-check CI requires.
- #80 feat(lean): Semantics.E8Sidon (1025 lines) -- Eisenstein coefficient
  identity E4^2 = E8 and the Sidon framework. E4_sq_eq_E8_coeff is fully proved
  (all Fourier-coefficient extraction machine-checked); the single residual gap
  is pinned to E4_sq_eq_E8_qExpansion (Mathlib lacks the valence formula /
  dim M8 = 1). 4 sorries + 1 axiom (e8_additive_completeness), all TODO(lean-port).
- #81 refactor(lean): Float-free FixedPoint core (integer-only sqrt/log2/expNeg).
  E8Sidon.lean kept at #80's final 1025-line version (the #81 intermediate
  438-line copy was overridden by merge order).
- #89 feat(lean): Semantics.RRC.PolyFactorIdentity -- short-sleeve polynomial
  detection at the zerocopy limb boundary; now imports Semantics.E8Sidon for
  sigma3/sigma7/convolutionLHS (single source of truth) instead of inlining them.

Conflict resolution:
- flake.nix -> canonical rs-surface removal (Garnix shutdown).
- scripts/math-first/* -> byte-identical across branches, clean.
- .cursorrules / AGENTS.md -> unified; baselines + sorry inventory refreshed.

Verification:
- lake build (default aggregator): 3573 jobs, 0 errors.
- lake build Semantics.RRC.PolyFactorIdentity (E8Sidon + FixedPoint + PolyFactor):
  3655 jobs, 0 errors. Witnesses verified (sigma7 4 = 16513, convolutionLHS 6 = 2350).
- Python tests: 68/68 pass.

Note: the "Workers Builds: researchstack" check is a preexisting external
Cloudflare build unrelated to this change (no branch touches 4-Infrastructure/cloudflare/).

Build: 3573 jobs (default), 3655 jobs (narrow), 0 errors
Co-Authored-By: Allaun Silverfox <bigdataiscoming+9i37y6j2@protonmail.com>
2026-06-16 02:01:31 +00:00

122 lines
3.8 KiB
Python
Executable file

#!/usr/bin/env python3
"""Require math evidence (receipt or Lean change) alongside math-track edits.
This script enforces the math-first contract: if a commit or PR touches files
in a math-track surface, at least one evidence file must also be present.
Usage:
# CI mode: compare against a base ref
python3 scripts/math-first/require_math_evidence.py --from-git-diff origin/main
# Pre-commit mode: check staged files
python3 scripts/math-first/require_math_evidence.py --staged
Exits 0 if:
- No math-track files are present in the changeset, OR
- At least one evidence file is also in the changeset
Exits 1 if math-track files are present but no evidence file accompanies them.
"""
from __future__ import annotations
import argparse
import subprocess
import sys
from pathlib import Path
# Math-track surface prefixes: files under these paths require evidence
MATH_TRACK_PREFIXES = (
"0-Core-Formalism/lean/Semantics/",
"6-Documentation/docs/distilled/",
"shared-data/data/stack_solidification/",
)
# Evidence patterns: if any changed file matches, the requirement is satisfied
EVIDENCE_PREFIXES = (
"shared-data/artifacts/deepseek_review/",
"0-Core-Formalism/lean/Semantics/",
)
EVIDENCE_FILES = (
"claims.yaml",
)
def get_changed_files_git_diff(base_ref: str) -> list[str]:
"""Get changed files by diffing against a base ref."""
result = subprocess.run(
["git", "diff", "--name-only", base_ref + "...HEAD"],
capture_output=True, text=True, check=False,
)
if result.returncode != 0:
# Fall back to two-dot diff
result = subprocess.run(
["git", "diff", "--name-only", base_ref],
capture_output=True, text=True, check=True,
)
return [f for f in result.stdout.strip().split("\n") if f]
def get_changed_files_staged() -> list[str]:
"""Get staged files for pre-commit hook."""
result = subprocess.run(
["git", "diff", "--cached", "--name-only"],
capture_output=True, text=True, check=True,
)
return [f for f in result.stdout.strip().split("\n") if f]
def is_math_track(path: str) -> bool:
return any(path.startswith(p) for p in MATH_TRACK_PREFIXES)
def is_evidence(path: str) -> bool:
if any(path.startswith(p) for p in EVIDENCE_PREFIXES):
return True
if path in EVIDENCE_FILES:
return True
return False
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--from-git-diff", metavar="BASE_REF",
help="Compare HEAD against BASE_REF")
group.add_argument("--staged", action="store_true",
help="Check staged files (pre-commit mode)")
args = parser.parse_args()
if args.staged:
changed = get_changed_files_staged()
else:
changed = get_changed_files_git_diff(args.from_git_diff)
if not changed:
print("No changed files")
return 0
math_files = [f for f in changed if is_math_track(f)]
if not math_files:
print("No math-track files in changeset — skipping evidence check")
return 0
evidence_files = [f for f in changed if is_evidence(f)]
if evidence_files:
print(f"OK: {len(math_files)} math-track file(s) with "
f"{len(evidence_files)} evidence file(s)")
return 0
# Math-track files present but no evidence
print("FAIL: math-track files changed but no evidence accompanies them:")
for f in math_files:
print(f" - {f}")
print("\nPlease include at least one of:")
print(" - A DeepSeek review receipt under shared-data/artifacts/deepseek_review/")
print(" - A Lean source file under 0-Core-Formalism/lean/Semantics/")
print(" - An update to claims.yaml")
return 1
if __name__ == "__main__":
raise SystemExit(main())