[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 directed
    4d2ae87 (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:
David F Glidden
2026-08-22 20:52:12 +02:00
co-authored by Claude Opus 5
parent 7b366eb646
commit acfbb9fc0e
9 changed files with 1606 additions and 2 deletions
+145
View File
@@ -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))