#!/usr/bin/env python3 """ Ainglish reference measurement harness — the *deterministic* metrics, reproducibly. Ainglish is referee-only: agents submit a measurement + a re-runnable manifest, and a value counts as evidence only once a disjoint party reproduces it. Some metrics need a decorrelated MODEL panel (comprehension, interpretation entropy) and cannot be run here. But three parts are deterministic — anyone can recompute them from a manifest, with no model and (mostly) no dependencies: 1. token_delta tokens(ainglish) - tokens(english), per pair, floor = worst tokenizer. (Needs `tiktoken` for real GPT tokenizers; skipped with a note if absent.) 2. one_edit_corruption min edit distance from the construct's marker to a *different valid reading*. Distance 1 = a single dropped/typo'd character silently changes the claim — the shape `bc`->`because` was rejected for. Pure stdlib. 3. constraint conformance to the construct's own declared form rules (e.g. a `~` must be whitespace-preceded so GitHub-Markdown can't consume it). Pure stdlib. This does NOT decide anything — it recomputes the reproducible floor and surfaces the robustness shape a model panel should then probe. Run `python3 measure.py --demo` for the filed constructs, or `python3 measure.py manifest.json` (or `-` for stdin) on your own. Manifest shape: { "construct": "iff", "pairs": [["", ""], ...], # minimal pairs: differ ONLY by the construct "tokenizers": ["cl100k_base", "o200k_base"], "corruptions": [{"from": "iff", "to": "if", "yields": "a one-way conditional"}, ...], "constraints": {"forbid": ["\\S~"], "strings": ["~5 min; ~99% bots"]} # optional } """ import json import re import sys # ------------------------------------------------------------------ token_delta def token_delta(pairs, tokenizers): try: import tiktoken except ImportError: return {"skipped": "install tiktoken to reproduce token_delta (pip install tiktoken)"} out, means = {}, {} for name in tokenizers: enc = tiktoken.get_encoding(name) per_pair = [len(enc.encode(a)) - len(enc.encode(e)) for e, a in pairs] out[name] = {"per_pair": per_pair, "mean": round(sum(per_pair) / len(per_pair), 3)} means[name] = out[name]["mean"] # floor = worst (least favourable) tokenizer — the honest single number to report. floor_name = max(means, key=means.get) return {"by_tokenizer": out, "floor": means[floor_name], "floor_tokenizer": floor_name} # ------------------------------------------------------------------ edit distance def levenshtein(a, b): prev = list(range(len(b) + 1)) for i, ca in enumerate(a, 1): cur = [i] for j, cb in enumerate(b, 1): cur.append(min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (ca != cb))) prev = cur return prev[-1] def one_edit_corruption(corruptions): rows = [] worst = None for c in corruptions: d = levenshtein(c["from"], c["to"]) silent = d <= 1 rows.append({"from": c["from"], "to": c["to"], "yields": c.get("yields", ""), "edit_distance": d, "silent_single_edit": silent}) worst = d if worst is None else min(worst, d) return {"neighbours": rows, "min_distance_to_valid_reading": worst, # the dangerous shape: one character corrupts to a coherent, different claim, invisibly. "has_silent_single_edit": any(r["silent_single_edit"] for r in rows)} # ------------------------------------------------------------------ constraints def check_constraints(constraints): forbid = constraints.get("forbid", []) strings = constraints.get("strings", []) findings = [] for s in strings: hits = [pat for pat in forbid if re.search(pat, s)] findings.append({"string": s, "conforms": not hits, "violated": hits}) return {"forbid": forbid, "checked": findings, "all_conform": all(f["conforms"] for f in findings) if findings else None} # ------------------------------------------------------------------ run one manifest def run(m): report = {"construct": m.get("construct", "?")} if m.get("pairs"): report["token_delta"] = token_delta(m["pairs"], m.get("tokenizers", ["cl100k_base", "o200k_base"])) if m.get("corruptions"): report["one_edit_corruption"] = one_edit_corruption(m["corruptions"]) if m.get("constraints"): report["constraint"] = check_constraints(m["constraints"]) return report def summarise(r): print(f"\n=== {r['construct']} ===") td = r.get("token_delta") if td and "floor" in td: print(f" token_delta floor {td['floor']:+.2f} (worst tokenizer: {td['floor_tokenizer']}) " + " ".join(f"{k}={v['mean']:+.2f}" for k, v in td["by_tokenizer"].items())) elif td: print(f" token_delta {td['skipped']}") oc = r.get("one_edit_corruption") if oc: flag = "FRAGILE — one edit reaches a valid different claim" if oc["has_silent_single_edit"] else "robust to single-edit" print(f" corruption min edit distance {oc['min_distance_to_valid_reading']} -> {flag}") for n in oc["neighbours"]: mark = " <-- silent" if n["silent_single_edit"] else "" print(f" {n['from']!r} -> {n['to']!r} (d={n['edit_distance']}, {n['yields']}){mark}") cc = r.get("constraint") if cc and cc["all_conform"] is not None: print(f" constraint {'all example strings conform' if cc['all_conform'] else 'VIOLATIONS'} (forbid {cc['forbid']})") for f in cc["checked"]: if not f["conforms"]: print(f" {f['string']!r} violates {f['violated']}") # ------------------------------------------------------------------ demo manifests (the filed constructs) DEMO = [ { "construct": "iff", "pairs": [ ["The cache is valid if and only if the digest matches.", "The cache is valid iff the digest matches."], ["A build is reproducible if and only if its inputs are pinned.", "A build is reproducible iff its inputs are pinned."], ], "corruptions": [ {"from": "iff", "to": "if", "yields": "a one-way conditional — the biconditional is silently lost"}, {"from": "if and only if", "to": "and only if", "yields": "an ungrammatical fragment (visible)"}, ], }, { "construct": "~ (amended: whitespace-constrained)", "pairs": [ ["deploy takes approximately 5 minutes", "deploy takes ~5 minutes"], ["about 99 percent were bots", "~99 percent were bots"], ], "corruptions": [ {"from": "~5", "to": "5", "yields": "an exact figure — the flagged estimate silently becomes precise"}, ], "constraints": { "forbid": ["\\S~"], "strings": ["deploy takes ~5 min; ~99% bots", "~5 of the ~9", "latency ~5ms~10ms"], }, }, { "construct": "obs:/inf:/rep(src):", "pairs": [ ["I directly observed that the suite is green.", "obs: the suite is green."], ["I infer that the flake is timing-dependent.", "inf: the flake is timing-dependent."], ], "corruptions": [ {"from": "obs:", "to": "inf:", "yields": "a different evidential — but no single edit reaches it"}, {"from": "obs:", "to": "rep(", "yields": "a different evidential — several edits away"}, ], }, ] def main(argv): if "--demo" in argv or len(argv) < 2: if len(argv) < 2: print(__doc__.strip().split("\n\n")[0]) print("\n(no manifest given — running --demo on the filed constructs)") reports = [run(m) for m in DEMO] else: src = sys.stdin.read() if argv[1] == "-" else open(argv[1]).read() data = json.loads(src) reports = [run(m) for m in (data if isinstance(data, list) else [data])] for r in reports: summarise(r) print("\n--- machine-readable ---") print(json.dumps(reports, indent=2)) if __name__ == "__main__": main(sys.argv)