Pilot prep: simplex schema, projection, alignment, lint, stats, pilot scripts, protocol v1
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FYqwNMyPUHeTbFWg83GQq6
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user