Files
Clayton Kim d81f519616 Transform UNSLOP around the core rewrite contract (#7)
* Optimize and harden eval loop

* Run behavioral acceptance on Luna

* Define core product acceptance gate

* Make behavioral acceptance honest and cheaper

* Harden clean no-op and contextual scanner gating

* Freeze blind Luna core benchmark v2

* Allow verified no-op benchmark results

* Keep advisory benchmark signals non-blocking

* Transform UNSLOP around the core rewrite contract

* Fix release lint failures

* Restore Python 3.8 compatibility

---------

Co-authored-by: Clayton Kim <claytonkim@users.noreply.github.com>
2026-08-05 14:01:19 -07:00

374 lines
14 KiB
Python

#!/usr/bin/env python3
"""Offline contribution scaffolder for new unslop AI-isms."""
from __future__ import annotations
import argparse
import hashlib
import json
import re
import subprocess
import sys
from datetime import date, datetime
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
CONTRIB_ROOT = ROOT / ".unslop" / "contrib"
TODO_MARKER = "TODO:"
SLUG_RE = re.compile(r"^[a-z0-9][a-z0-9_-]{0,63}$")
GATE_COMMANDS = [
["python3", "evals/check.py", "--full"],
]
def read_text(path: Path) -> str:
try:
return path.read_text(encoding="utf-8")
except OSError as exc:
print(json.dumps({"error": f"could not read {path}: {exc}"}))
raise SystemExit(2) from exc
def write_json(path: Path, data: object) -> None:
path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8")
def sha256_text(text: str) -> str:
return hashlib.sha256(text.encode("utf-8")).hexdigest()
def word_count(text: str) -> int:
return len(re.findall(r"[A-Za-z0-9']+", text))
def shorten(text: str, limit: int = 72) -> str:
one_line = " ".join(text.split())
if len(one_line) <= limit:
return one_line
return one_line[: limit - 1].rstrip() + "..."
def run_scanner(command: list[str], text: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(command, input=text, capture_output=True, text=True, cwd=ROOT, timeout=30)
def scanner_findings(text: str) -> list[dict[str, object]]:
findings: list[dict[str, object]] = []
for name, command in (
("banned_phrase", ["python3", "scripts/banned_phrase_scan.py"]),
("structure", ["python3", "scripts/structure_scan.py"]),
):
proc = run_scanner(command, text)
try:
data = json.loads(proc.stdout)
except json.JSONDecodeError:
data = {}
violations = data.get("violations", [])
if name == "structure":
violations = [
{
"phrase": flag.get("metric", ""),
"category": flag.get("metric", ""),
"severity": flag.get("severity", ""),
}
for flag in data.get("flags", [])
]
for violation in violations:
findings.append(
{
"scanner": name,
"phrase": violation.get("phrase", ""),
"category": violation.get("category", ""),
"severity": violation.get("severity", ""),
}
)
return findings
def redaction_pairs(values: list[str]) -> list[tuple[str, str]]:
pairs = []
for value in values:
if "=" not in value:
print(json.dumps({"error": "--redact values must use orig=REPL"}))
raise SystemExit(2)
orig, repl = value.split("=", 1)
pairs.append((orig, repl))
return pairs
def apply_redactions(text: str, tell: str, pairs: list[tuple[str, str]]) -> str:
before_count = text.count(tell)
redacted = text
for orig, repl in pairs:
redacted = redacted.replace(orig, repl)
if before_count == 0 or redacted.count(tell) != before_count:
print(json.dumps({"error": "redaction alters the specimen", "tell": tell}))
raise SystemExit(4)
return redacted
def row_fn(slug: str, tell: str, snippet: str) -> dict[str, object]:
assertion_tell = tell.casefold()
return {
"id": f"CONTRIB-FN-{slug}",
"target": "script",
"category": "scanner_false_negative",
"stdin": snippet,
"assertions": [
{"type": "json", "path": "total_violations", "gte": 1},
{"type": "violation_phrase_contains", "value": assertion_tell},
],
}
def row_fp_template(slug: str, category: str, tell: str) -> dict[str, object]:
return {
"id": f"CONTRIB-FP-{slug}",
"category": "scanner_false_positive",
"protects": category,
"target": "script",
"stdin": "TODO: add a literal or domain-specific use that should remain clean.",
"assertions": [{"type": "json", "path": "total_violations", "equals": 0}],
}
def render_report(
manifest: dict[str, object],
snippet: str,
gate_results: str = "",
include_rec: bool = False,
) -> str:
redactions = manifest.get("redactions", [])
redaction_note = "names/numbers redacted; tell verbatim" if redactions else "none"
rows = [
f"| CONTRIB-FN-{manifest['pattern_name']} | FN | exact specimen flags `{manifest['tell']}` |",
f"| CONTRIB-FP-{manifest['pattern_name']} | FP | literal-use protection for `{manifest['tell']}` |",
]
if include_rec:
rows.append("| CONTRIB-REC | REC | existing-word recall still flags |")
quoted = "\n".join(f"> {line}" if line else ">" for line in snippet.splitlines())
pattern_added = manifest.get(
"pattern_added",
f"TODO: regex or phrase for `{manifest['tell']}`",
)
return (
f"# Add {manifest['category']} pattern: {shorten(str(manifest['tell']))}\n\n"
"## The specimen\n\n"
f"{quoted}\n\n"
f"- Source genre: {manifest.get('source_genre', 'TODO: source genre')}\n"
f"- Date: {manifest['date']}\n"
f"- Redaction note: {redaction_note}\n\n"
"## Why it's an AI-ism\n\n"
f"{manifest.get('rationale', 'TODO: explain why this phrase is a reusable AI-writing tell in 2-4 sentences.')}\n\n"
"## Detection\n\n"
f"- Pattern added: {pattern_added}\n"
f"- Severity: {manifest.get('severity', 'TODO: hard or soft')}\n"
f"- Gating rationale: {manifest.get('gating_rationale', 'TODO: explain literal-use boundary')}\n"
"- Catalog entry location: references/taboo-phrases.md\n\n"
"## Evals\n\n"
"| row id | kind | what it pins |\n"
"|---|---|---|\n"
+ "\n".join(rows)
+ "\n\n"
"The FN stdin is the unmodified specimen after approved redaction.\n\n"
"## Gate results\n\n"
f"{gate_results or 'TODO: paste gate tails from verify.'}\n\n"
"## Checklist\n\n"
"- [ ] eval-first (row was red before the pattern)\n"
"- [ ] literal-use FP row included\n"
"- [ ] REC row if an existing word was gated\n"
"- [ ] catalog + scanner parity green\n"
"- [ ] coverage gate green (pattern exercised)\n"
"- [ ] snippet publication approved by the user\n"
)
def cmd_precheck(args: argparse.Namespace) -> int:
snippet = read_text(Path(args.snippet_file))
findings = scanner_findings(snippet)
if findings:
print(json.dumps({"status": "already_covered", "findings": findings}, indent=2, sort_keys=True))
return 3
print(json.dumps({"status": "clean", "words": word_count(snippet)}, indent=2, sort_keys=True))
return 0
def cmd_scaffold(args: argparse.Namespace) -> int:
if not SLUG_RE.match(args.pattern_name):
print(
json.dumps(
{
"error": f"invalid pattern name: {args.pattern_name!r}; use lowercase letters, digits, - or _",
}
)
)
return 2
source = Path(args.snippet)
snippet = read_text(source)
if args.tell not in snippet:
print(json.dumps({"error": "tell substring not found", "tell": args.tell}))
return 2
try:
manifest_date = datetime.strptime(args.date, "%Y-%m-%d").date().isoformat()
except ValueError:
print(json.dumps({"error": "--date must use YYYY-MM-DD", "date": args.date}))
return 2
redactions = redaction_pairs(args.redact or [])
redacted = apply_redactions(snippet, args.tell, redactions)
bundle = CONTRIB_ROOT / args.pattern_name
bundle.mkdir(parents=True, exist_ok=True)
manifest = {
"category": args.category,
"date": manifest_date,
"pattern_name": args.pattern_name,
"pre_redaction_sha256": sha256_text(snippet),
"post_redaction_sha256": sha256_text(redacted),
"redactions": [{"from": orig, "to": repl} for orig, repl in redactions],
"tell": args.tell,
"word_count": word_count(redacted),
}
write_json(bundle / "row_fn.json", row_fn(args.pattern_name, args.tell, redacted))
write_json(bundle / "row_fp_TEMPLATE.json", row_fp_template(args.pattern_name, args.category, args.tell))
write_json(bundle / "manifest.json", manifest)
(bundle / "snippet.txt").write_text(redacted, encoding="utf-8")
(bundle / "report.md").write_text(render_report(manifest, redacted), encoding="utf-8")
print(json.dumps({"bundle": str(bundle.relative_to(ROOT)), "status": "scaffolded"}, indent=2, sort_keys=True))
return 0
def run_row(row: dict[str, object]) -> subprocess.CompletedProcess[str]:
return subprocess.run(
["python3", "scripts/banned_phrase_scan.py"],
input=str(row.get("stdin", "")),
capture_output=True,
text=True,
cwd=ROOT,
timeout=30,
)
def row_assertions_pass(row: dict[str, object], proc: subprocess.CompletedProcess[str]) -> bool:
try:
data = json.loads(proc.stdout)
except json.JSONDecodeError:
return False
for assertion in row.get("assertions", []):
if assertion.get("type") == "json":
cur = data
for part in assertion["path"].split("."):
cur = cur[int(part)] if isinstance(cur, list) else cur[part]
if "gte" in assertion and not cur >= assertion["gte"]:
return False
if "equals" in assertion and cur != assertion["equals"]:
return False
elif assertion.get("type") == "violation_phrase_contains":
phrases = [v.get("phrase", "") for v in data.get("violations", [])]
needle = str(assertion["value"]).casefold()
if not any(needle in str(phrase).casefold() for phrase in phrases):
return False
else:
return False
return True
def tail(text: str, lines: int = 12) -> str:
split = text.splitlines()
return "\n".join(split[-lines:])
def verify_bundle(bundle: Path, run_gates: bool = True) -> tuple[bool, str]:
if not bundle.exists():
return False, "missing bundle"
row_path = bundle / "row_fn.json"
report_path = bundle / "report.md"
manifest_path = bundle / "manifest.json"
snippet_path = bundle / "snippet.txt"
for path in (row_path, report_path, manifest_path, snippet_path):
if not path.exists():
return False, f"missing {path.name}"
report = report_path.read_text(encoding="utf-8")
if TODO_MARKER in report:
return False, "report contains TODO markers"
row = json.loads(row_path.read_text(encoding="utf-8"))
snippet = snippet_path.read_text(encoding="utf-8")
if row.get("stdin") != snippet:
return False, "row_fn stdin does not equal snippet.txt byte-for-byte"
proc = run_row(row)
assertion_ok = row_assertions_pass(row, proc)
red_first = not assertion_ok
gate_results = [f"red-first: {'ok' if red_first else 'already green'}"]
ok = red_first
if not red_first:
ok = True
gate_results[0] = "red-first: already green; proposed pattern appears active"
if run_gates:
for command in GATE_COMMANDS:
proc = subprocess.run(command, capture_output=True, text=True, cwd=ROOT, timeout=120)
gate_results.append(
"### "
+ " ".join(command)
+ f"\n\n```text\nexit={proc.returncode}\n{tail(proc.stdout or proc.stderr)}\n```"
)
ok = ok and proc.returncode == 0
final = "\n\n".join(gate_results)
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
report_path.write_text(render_report(manifest, snippet, final, (bundle / "row_rec.json").exists()), encoding="utf-8")
return ok, final
def cmd_verify(args: argparse.Namespace) -> int:
ok, message = verify_bundle(Path(args.bundle), run_gates=not args.no_gates)
print(message)
return 0 if ok else 1
def cmd_report(args: argparse.Namespace) -> int:
bundle = Path(args.bundle)
if not bundle.exists():
print(json.dumps({"error": "missing bundle", "bundle": str(bundle)}))
return 2
manifest = json.loads((bundle / "manifest.json").read_text(encoding="utf-8"))
snippet = (bundle / "snippet.txt").read_text(encoding="utf-8")
report = (bundle / "report.md").read_text(encoding="utf-8")
gate_marker = "## Gate results\n\n"
checklist_marker = "\n\n## Checklist"
gate_results = ""
if gate_marker in report and checklist_marker in report:
gate_results = report.split(gate_marker, 1)[1].split(checklist_marker, 1)[0]
print(render_report(manifest, snippet, gate_results, (bundle / "row_rec.json").exists()).rstrip())
return 0
def parse_args(argv: list[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
sub = parser.add_subparsers(dest="command", required=True)
precheck = sub.add_parser("precheck")
precheck.add_argument("snippet_file")
precheck.set_defaults(func=cmd_precheck)
scaffold = sub.add_parser("scaffold")
scaffold.add_argument("--snippet", required=True)
scaffold.add_argument("--tell", required=True)
scaffold.add_argument("--category", required=True)
scaffold.add_argument("--pattern-name", required=True)
scaffold.add_argument("--redact", action="append")
scaffold.add_argument("--date", default=date.today().isoformat())
scaffold.set_defaults(func=cmd_scaffold)
verify = sub.add_parser("verify")
verify.add_argument("--bundle", required=True)
verify.add_argument("--no-gates", action="store_true")
verify.set_defaults(func=cmd_verify)
report = sub.add_parser("report")
report.add_argument("--bundle", required=True)
report.set_defaults(func=cmd_report)
return parser.parse_args(argv)
def main(argv: list[str]) -> int:
args = parse_args(argv)
return args.func(args)
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))