Files
ruvnet__ruflo/v3/docs/spec/conformance/recompute_reference.py
ruv 66fbe7ce12 docs(adr): make ADR-322C recomputation reproducible from the spec alone
Closes the gap raised by ruflo#3069: ADR-322C required independent
statistical recomputation but specified only the bootstrap seed, not the
generator it drives. A verifier could not reproduce a receipt's statistics
from the document - the only way to recompute correctly was to read
flywheel-receipt.ts, which is a copy rather than an independent check.

Appends an "Update (2026-08-19)" section per this repo's ADR convention
(ADR-380) rather than editing the text above. It makes normative: the LCG
and its constants, the seeding rule and exact byte slice, the resampling
procedure and draw order, the quantile rule, tie/edge cases, and the
scale-12 decimal encoding the statistics must reproduce byte-for-byte. It
also records the ledger divergence (flat unsigned commits[] on main vs the
content-addressed segments and signed head the ADR describes, with
flywheel-ledger-head/v1 unused), the disabled projection path, and that
strictness is versioned.

Acceptance is demonstrated, not asserted: conformance/recompute_reference.py
is written only from the amendment prose, in a different language from the
reference implementation, and reproduces the fixture exactly.

Adds receipt-bootstrap-reference.example.json because the existing example
turned out not to discriminate - its deltas take two distinct values, so a
wrong seed slice, wrong byte order, or entirely different LCG constants all
yield the same 2.5th percentile. The new fixture has heterogeneous deltas
and separates all three.

Records one defect found while building it (gap G5): createFlywheelReceipt
computes statistics from full-precision means while storing scale-12
strings, so a receipt whose mean needs more than twelve decimals fails its
own verifyFlywheelReceipt. Reproduced at mean 0.7687083333333332. Existing
fixtures use exactly-representable means, which is why it was not caught.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-08-19 22:01:21 -04:00

127 lines
4.5 KiB
Python

"""
Independent reference implementation of the ADR-322C bootstrap recomputation.
Written ONLY from the prose of ADR-322C's "Update (2026-08-19)" amendment, with
no reference to flywheel-receipt.ts. Deliberately in a different language from
the reference implementation: an independent check written by reading the TypeScript
would be a copy, not a check (ruflo#3069).
It exists to answer one question -- is the specification sufficient to reimplement
from? -- and doubles as a runnable oracle for consumers building their own verifier.
Usage:
python3 recompute_reference.py ../examples/receipt-bootstrap-reference.example.json
Exits 0 when the recomputed statistics match the receipt's recorded ones.
Use receipt-bootstrap-reference.example.json, not receipt-accepted.example.json:
only the former has heterogeneous per-task deltas, so only the former actually
discriminates a wrong PRNG (see witness-receipt-contract.md section 6.1).
"""
import hashlib
import json
import sys
def seed_state(corpus_hash, candidate_id, baseline_ref, evaluation_run_id):
"""Section 1: SHA-256 over the concatenation, no separator."""
data = ("ruflo/bootstrap/v1" + corpus_hash + candidate_id
+ baseline_ref + evaluation_run_id).encode("utf-8")
digest = hashlib.sha256(data).digest()
seed_hex = digest.hex()
state = int.from_bytes(digest[0:4], "big") # FIRST FOUR BYTES ONLY
return seed_hex, state
def make_rng(state):
"""Section 1: LCG. First draw uses the advanced state."""
s = state
def draw():
nonlocal s
s = (1664525 * s + 1013904223) % (2 ** 32)
return s / (2 ** 32)
return draw
def bootstrap(deltas, draw, iterations=10000):
"""Section 2: exactly n draws per iteration, consumed in sequence."""
n = len(deltas)
if n == 0:
return [0.0] * iterations
means = []
for _ in range(iterations):
total = 0.0
for _ in range(n):
total += deltas[int(draw() * n)]
means.append(total / n)
return means
def decimal12(value):
"""Section 4: scale 12, strip trailing zeros then trailing point, '' or '-0' -> '0'."""
rendered = f"{value:.12f}"
if "." in rendered:
rendered = rendered.rstrip("0").rstrip(".")
if rendered in ("", "-0"):
return "0"
return rendered
def recompute(receipt_payload):
p = receipt_payload
deltas = [float(d) for d in p["heldOutDeltas"]]
baseline = float(p["baselineScore"])
candidate = float(p["candidateScore"])
frozen_anchor = float(p["statistics"]["frozenAnchorRegression"])
iterations = p["statistics"]["iterations"]
metric_epsilon = 1e-12
seed_hex, state = seed_state(
p["corpusHash"], p["candidateId"], p["baselineRef"], p["evaluationRunId"]
)
means = bootstrap(deltas, make_rng(state), iterations)
probability = sum(1 for m in means if m > 0) / iterations
ci_low = sorted(means)[int(0.025 * iterations)] # 0-based order statistic
# Section 3
relative_lift = (candidate - baseline) / max(abs(baseline), metric_epsilon)
significant = probability >= 0.95 and ci_low > 0
accepted = relative_lift >= 0.02 and significant and frozen_anchor <= 0
decision = "accepted" if (accepted and all(p["gates"].values())) else "rejected"
return {
"seedHex": seed_hex,
"relativeLift": decimal12(relative_lift),
"pairedBootstrapProbability": decimal12(probability),
"pairedBootstrapDeltaCILow95": decimal12(ci_low),
"frozenAnchorRegression": decimal12(frozen_anchor),
"significant": significant,
"accepted": accepted,
"decision": decision,
}
if __name__ == "__main__":
receipt = json.load(open(sys.argv[1]))
payload = receipt["payload"]
got = recompute(payload)
want = {
"seedHex": payload["statistics"]["seedHex"],
"relativeLift": payload["statistics"]["relativeLift"],
"pairedBootstrapProbability": payload["statistics"]["pairedBootstrapProbability"],
"pairedBootstrapDeltaCILow95": payload["statistics"]["pairedBootstrapDeltaCILow95"],
"frozenAnchorRegression": payload["statistics"]["frozenAnchorRegression"],
"significant": payload["statistics"]["significant"],
"accepted": payload["statistics"]["accepted"],
"decision": payload["decision"],
}
ok = True
for k in want:
match = got[k] == want[k]
ok = ok and match
print(f"{'OK ' if match else 'FAIL'} {k}: got={got[k]!r} want={want[k]!r}")
print("\nRESULT:", "spec is sufficient" if ok else "SPEC INSUFFICIENT")
sys.exit(0 if ok else 1)