#!/usr/bin/env python3 """ Fool bones derivation — PENDING-149 §6 / §6b. Deterministic. No salt. No reroll path. Nothing is cached: the caller supplies the two seed components and the bones are recomputed from them every time. This file implements the FILED RULE (FOOL-SEED-RULE.md). Where this code and the filed rule disagree, THE FILED RULE GOVERNS and this file is the defect. Usage: derive_fool.py --beacon # bones from a pulse value derive_fool.py --selftest # determinism + range checks, no network """ import argparse, hashlib, subprocess, sys # ---- the filed rule's constants. Do not edit without amending the filed rule. ---- PROVENANCE_COMMIT = "4d2ae87a4e5350c4d3bb3aa50f9544b521d9c53d" PROVENANCE_PATH = "CLAUDE.md" PROVENANCE_REPO = "/Users/davidglidden/dotfiles" PROVENANCE_SHA256 = "2d6e250a347d25698fb147f80e2dababbb930c4b3b3f9bb822478f360153120d" AXES = ["SUCCESSION", "ABSENCE", "AIM", "SCALE", "STAKE"] # §5, ratified order PEAK_RANGE = (85, 100) # "near max" — executor-specified, filed pre-beacon DUMP_RANGE = (0, 15) # "near floor" — executor-specified, filed pre-beacon SCATTER_RANGE = (25, 75) # "scattered" — executor-specified, filed pre-beacon def provenance_sha() -> str: """SHA-256 of CLAUDE.md at the named past commit. Recomputed, never trusted from the constant.""" blob = subprocess.run( ["git", "-C", PROVENANCE_REPO, "cat-file", "-p", f"{PROVENANCE_COMMIT}:{PROVENANCE_PATH}"], capture_output=True, check=True).stdout got = hashlib.sha256(blob).hexdigest() if got != PROVENANCE_SHA256: raise SystemExit(f"STOP: provenance blob does not match the filed rule.\n" f" filed: {PROVENANCE_SHA256}\n got: {got}") return got def fnv1a_32(data: bytes) -> int: h = 0x811C9DC5 for b in data: h ^= b h = (h * 0x01000193) & 0xFFFFFFFF return h def mulberry32(a: int): """Reference Mulberry32, 32-bit wrapped to match the JS original exactly: a = a + 0x6D2B79F5 | 0 t = Math.imul(a ^ a >>> 15, 1 | a) t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t return ((t ^ t >>> 14) >>> 0) / 4294967296 """ M = 0xFFFFFFFF state = a & M def imul(x, y): r = (x * y) & M return r - 0x100000000 if r & 0x80000000 else r def rnd(): nonlocal state state = (state + 0x6D2B79F5) & M a_ = state t = imul(a_ ^ (a_ >> 15), 1 | a_) & M t = ((t + imul(t ^ (t >> 7), 61 | t)) & M) ^ t return ((t ^ (t >> 14)) & M) / 4294967296.0 return rnd def draw_int(rnd, lo: int, hi: int) -> int: return lo + int(rnd() * (hi - lo + 1)) def derive(beacon_output_value: str) -> dict: beacon = beacon_output_value.strip().lower() if not beacon or any(c not in "0123456789abcdef" for c in beacon): raise SystemExit("STOP: beacon outputValue must be non-empty lowercase hex.") prov = provenance_sha() seed_string = prov + beacon seed = hashlib.sha256(seed_string.encode()).hexdigest() rnd = mulberry32(fnv1a_32(seed.encode())) order = list(range(len(AXES))) # Fisher-Yates over the PRNG for i in range(len(order) - 1, 0, -1): j = int(rnd() * (i + 1)) order[i], order[j] = order[j], order[i] stats = {} stats[AXES[order[0]]] = draw_int(rnd, *PEAK_RANGE) stats[AXES[order[1]]] = draw_int(rnd, *DUMP_RANGE) for k in order[2:]: stats[AXES[k]] = draw_int(rnd, *SCATTER_RANGE) return {"provenance_sha256": prov, "beacon_outputValue": beacon, "seed_string": seed_string, "seed": seed, "peak": AXES[order[0]], "dump": AXES[order[1]], "stats": {a: stats[a] for a in AXES}} def selftest() -> int: """No network. Fixed synthetic vectors only — never a live or near-future pulse.""" ok = True V1 = "0" * 128 V2 = "f" * 128 r1, r1b, r2 = derive(V1), derive(V1), derive(V2) checks = [ ("determinism: same input twice -> identical bones", r1 == r1b), ("sensitivity: different beacon -> different seed", r1["seed"] != r2["seed"]), ("provenance recomputed matches filed rule", r1["provenance_sha256"] == PROVENANCE_SHA256), ("seed_string is prov||beacon, no salt", r1["seed_string"] == PROVENANCE_SHA256 + V1), ("exactly five axes", sorted(r1["stats"]) == sorted(AXES)), ("peak in range", PEAK_RANGE[0] <= r1["stats"][r1["peak"]] <= PEAK_RANGE[1]), ("dump in range", DUMP_RANGE[0] <= r1["stats"][r1["dump"]] <= DUMP_RANGE[1]), ("peak is not dump", r1["peak"] != r1["dump"]), ("three scattered in range", all(SCATTER_RANGE[0] <= v <= SCATTER_RANGE[1] for a, v in r1["stats"].items() if a not in (r1["peak"], r1["dump"]))), ("no floor: dump can reach the bottom of its range", min(derive(f"{i:0128x}")["stats"][derive(f"{i:0128x}")["dump"]] for i in range(200)) <= DUMP_RANGE[0] + 1), ] # --- normalization: the jurist's pre-25th condition. outputValue is served UPPERCASE. --- UP = "A1B2C3D4E5F6" * 10 + "ABCDEFAB" # 128 chars, uppercase hex LOW = UP.lower() r_up, r_low = derive(UP), derive(LOW) # independent expectation, computed here rather than read back from derive() import hashlib as _h expected_seed = _h.sha256((PROVENANCE_SHA256 + LOW).encode()).hexdigest() wrong_seed = _h.sha256((PROVENANCE_SHA256 + UP ).encode()).hexdigest() checks += [ ("UPPERCASE input normalizes: bones identical to lowercase", r_up == r_low), ("UPPERCASE input matches independently computed seed", r_up["seed"] == expected_seed), ("recorded beacon field is stored lowercased", r_up["beacon_outputValue"] == LOW), ("NEGATIVE CONTROL: un-normalized input WOULD give a different seed " "(so the check above can fail)", expected_seed != wrong_seed), ] # positive control: the PRNG must actually move both peak and dump around the axes peaks = {derive(f"{i:0128x}")["peak"] for i in range(200)} dumps = {derive(f"{i:0128x}")["dump"] for i in range(200)} checks.append(("POSITIVE CONTROL: peak lands on all five axes over 200 draws", peaks == set(AXES))) checks.append(("POSITIVE CONTROL: dump lands on all five axes over 200 draws", dumps == set(AXES))) for name, passed in checks: print(f" {'PASS' if passed else 'FAIL'} {name}") ok &= passed print(f"\n{'SELFTEST PASSED' if ok else 'SELFTEST FAILED — do not run against a live pulse'}") return 0 if ok else 1 if __name__ == "__main__": p = argparse.ArgumentParser() p.add_argument("--beacon"); p.add_argument("--selftest", action="store_true") a = p.parse_args() if a.selftest: sys.exit(selftest()) if not a.beacon: p.error("--beacon required (or --selftest)") import json; print(json.dumps(derive(a.beacon), indent=2))