[PROPOSAL] Fool seed rule filed before the beacon; two unresolvable values caught (PENDING-149)
§4 steps 1-4 discharged and pushed ahead of the 2026-08-25T12:00:00Z beacon: ratified axes recorded in writing, seed derivation rule filed, retirement and regeneration criteria filed, derivation implemented and self-tested. Two values in the jurist's §6b block did not resolve, and both are corrected in the open rather than absorbed: - the provenance commit's stated rationale was false.3b0730d5(2026-08-06) postdates the fool's conception by five days, its subject names the PENDING-89 docket, and Constraint 6 is already in it. Steward directed4d2ae87(2026-07-28), where Constraint 6 occurs zero times. - the retrieval URL returns HTTP 302 and an empty body, redirecting to an HTML page. Filed verbatim, the 25th would have produced no pulse and the UNAVAILABILITY clause would have run a 24-hour retry against an address that can never return one. Found only because §6b directs a historical dry run. Also measured: outputValue is served UPPERCASE, so the rule's "lowercased before use" is load-bearing; and curl reaches the beacon where python urllib times out. Nothing derived. Target pulse not fetched. CLAUDE.md untouched (PENDING-150). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JQKeKY9T9d95KpvHwwok8T
This commit is contained in:
co-authored by
Claude Opus 5
parent
7b366eb646
commit
acfbb9fc0e
Executable
+145
@@ -0,0 +1,145 @@
|
||||
#!/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 <outputValue-hex> # 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),
|
||||
]
|
||||
# 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 <outputValue-hex> required (or --selftest)")
|
||||
import json; print(json.dumps(derive(a.beacon), indent=2))
|
||||
Reference in New Issue
Block a user