Pilot prep: simplex schema, projection, alignment, lint, stats, pilot scripts, protocol v1
ci / python (pull_request) Successful in 17s
ci / lean (pull_request) Successful in 1m10s
ci / image (pull_request) Has been skipped

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYqwNMyPUHeTbFWg83GQq6
This commit is contained in:
2026-10-22 05:52:28 +00:00
parent 3e0782c62a
commit ca98703538
19 changed files with 2024 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
"""Cheap static checks for formalizations that compile and are probably wrong.
These are a baseline for the fidelity filter, not a replacement for one: each looks
at the projected roles and the text of the declaration only, with no model and no
Lean. They catch encoding hazards (natural-number subtraction, integer division),
binders the statement never uses, and goals that say nothing.
"""
from __future__ import annotations
import re
from .project import Projection
from .schema import KIND_FACT, KIND_GOAL, KIND_OBJECT
_NAT = re.compile(r"\b(ℕ|Nat)\b")
_OTHER_NUMBERS = re.compile(r"[ℤℚℝℂ]|\b(Int|Rat|Real|Complex)\b")
_SUBTRACTION = re.compile(r"[\w)\]]\s*-\s*[\w(]")
_DIVISION = re.compile(r"[\w)\]]\s*/\s*[\w(]")
_IDENT = re.compile(r"[A-Za-z_][A-Za-z0-9_']*")
def lint(projection: Projection) -> list[str]:
findings: list[str] = []
if projection.degenerate:
findings.append("degenerate")
texts = [r.type_text for r in projection.roles if r.kind in (KIND_FACT, KIND_GOAL)]
body = " ".join(texts)
declared = " ".join(r.type_text for r in projection.roles if r.kind == KIND_OBJECT)
for role in projection.roles:
if role.kind != KIND_OBJECT or role.attrs.get("binder_kind") != "explicit":
continue
if role.type_text.strip().startswith(("Type", "Sort")):
continue # a carrier: used by the instances that constrain it
used = set(_IDENT.findall(body)) | set(_IDENT.findall(declared.replace(role.type_text, "")))
if role.name != "_" and role.name not in used:
findings.append(f"unused_binder:{role.name}")
nat_only = _NAT.search(declared + " " + body) and not _OTHER_NUMBERS.search(declared + body)
if nat_only and _SUBTRACTION.search(body):
findings.append("nat_subtraction")
if (_NAT.search(declared) or re.search(r"\b(ℤ|Int)\b", declared)) and _DIVISION.search(body):
findings.append("integer_division")
goal = next((r for r in projection.roles if r.kind == KIND_GOAL), None)
if goal is not None and goal.type_text.strip() in ("", "True", "False", "1 = 1", "0 = 0"):
findings.append("trivial_goal")
return findings