90 lines
4.0 KiB
Python
Raw Normal View History

Answer the fork-loss handoff: the section's residual is ~17x overstated, and it misses the real bias Settles E1-E4 and E6 of handoff-fork-loss-validation.md against spec d6fd7648. E1 costs nothing and reframes everything: analysis-block-times-blend-network.md sets blending_delay as a FIXED per-hop dwell (the 3d+5 max-delay arithmetic gives 14 s at d=3 and 11 s at d=2, matching its prose), not a mean or a bound. The simulator's Uniform(0, delta_max) matches a 2 s dwell in the mean at delta_max = 4, so D_vis = 8 s and rho = 0.27 -- inside the committed 40-replicate paired design band, which answers C1-C3 from data of record. C1 refuted: every U>=1 cell sits at 0.9985-0.9997, not 0.986. C2's mechanism is right but its size is ~17x over: the paired first-fork cost is 0.08 pp pooled (95% CI [0.03, 0.13], t = 3.08), resolved only because the arms share streams -- the U=0 negative control is exactly 0.00000 +- 0.00000. C3 is refuted in the UNFAVOURABLE direction: the no-uncle loss is 33% at N=1000 and 34.6% at N=5000 (42% / 49.5% at delta_max = 8), so the section understates what uncles buy by about half. C4 stands with ~7x margin (U=3 still recovers at rho = 1.87). C5 is right in effect, wrong in wording -- the knee is at W_abs ~ 5, so the spec's 10 is ~2x above it, which is "has margin", not "never binds". C6 is the section's real omission. The deployed estimator quantises the target rate at PRECISION = 1e3, and measured in the full dynamics that reads 1.01026 +- 0.00056 against a closed form of 1.0101 -- a 1.0% bias ~13x the first-fork cost the section is concerned with, opposite in sign, removed by a one-constant change. It could not be measured before because PRECISION was a module constant pinned at the RECOMMENDED 1e6; f_precision is now a config field, appended to the RNG key only when non-default so no committed run moves. Also from the guide: uncle_window_slots now floors rather than rounds, matching w_u := floor(W/f) (identical at the defaults; matters only for the W and f sweeps). Reviewed sec 4.3's argument as sec 6 asks, and it holds -- inclusion stayed soft ("may reference fewer uncles than it could ... and its block remains valid"), so row 10, the anti-mandate argument and the suppress adversary are all unaffected; only the CONTENT of a reference became validity-gated. One correction: the "no incentive to deviate" clause does still exist, so sec 8.5's implication (ii) is live, not moot. E5 -- the jitter diagnostic, and the only experiment that could invalidate the report rather than the section -- is not run and is flagged as such. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 18:45:00 +02:00
"""What the DEPLOYED chain would read at the spec's own operating point — handoff E1/E2/E6.
The report measures the mechanism: it drives the estimator to exact `f`, so its numbers isolate
fork loss from every other effect. That is the right default for design questions and the wrong
one for "what will the deployed chain read", because the spec's estimator quantises the target
rate `cryptarchia-total-stake-inference.md` carries `const PRECISION: u64 = 1e3`, so
`f_p = 0.033` at `f = 1/30` and the recursion drives density to a target ~1 % below `f`.
E1 pins the operating point from `analysis-block-times-blend-network.md`: `blending_delay` is a
FIXED per-hop dwell of 2 s (the `3d+5` max-delay arithmetic gives 11 s at d=2 and 14 s at d=3,
matching the prose), so the simulator's `Uniform(0, delta_max)` matches it in the mean at
`delta_max = 4` -> `D_vis ~ 8 s`, `rho ~ 0.27`.
Three arms, everything else identical:
exact f fixed_point=False the report's convention -> expect 1.000
spec fixed_point=True, 1e3 what the chain does today -> expect ~1.010
proposed fixed_point=True, 1e6 the report's recommendation -> expect ~1.00001
The point of running rather than quoting `theory.fixed_point_bias`: the closed form predicts the
offset in isolation, and this confirms it survives the full per-node dynamics at the deployment's
actual load, alongside the fork loss rather than instead of it.
Run: python scripts/spec_point.py (writes runs/spec_point.parquet)
"""
from __future__ import annotations
from pathlib import Path
import pandas as pd
from joblib import Parallel, delayed
from tsi_sim.config import SimConfig
from tsi_sim.engine import run_trajectory
from tsi_sim.theory import fixed_point_bias
HERE = Path(__file__).resolve().parent.parent
RUNS = HERE / "runs"
RUNS.mkdir(exist_ok=True)
EPOCHS = 20
REPS = 20
N_JOBS = 6
# The spec's operating point (E1), with the spec's own MAX_UNCLES rather than the report's U = 2.
SPEC_POINT = dict(n_nodes=1000, stake_dist="pareto", topology="blend", degree=6,
link_latency_mean=0.5, link_latency_dist="geo", blend_hops=3,
blend_delay_max=4.0, max_uncles=4, uncle_strategy="oldest",
window_absorption=10.0, k=2160, epochs=EPOCHS,
genesis_d_factor=0.5, early_stop=True)
ARMS = [("exact f (report convention)", False, 1_000_000),
("spec today (PRECISION = 1e3)", True, 1_000),
("recommended (PRECISION = 1e6)", True, 1_000_000)]
def _cell(label: str, fixed_point: bool, precision: int, rep: int) -> dict:
cfg = SimConfig(**SPEC_POINT, fixed_point=fixed_point, f_precision=precision, replicate=rep)
t = pd.DataFrame(run_trajectory(cfg))
t = t[t.epoch >= t.epoch.max() // 2]
return dict(arm=label, fixed_point=fixed_point, f_precision=precision, rep=rep,
mean_ratio=float(t.mean_ratio.mean()),
fork_rate=float(t.fork_rate.mean()),
p_ref=float(t.p_ref.mean()),
range_ratio=float(t.range_ratio.max()))
def main() -> None:
print("=== the spec's operating point: delta_max = 4, D_vis ~ 8 s, rho ~ 0.27, U = 4 ===")
jobs = [(lab, fp, pr, r) for lab, fp, pr in ARMS for r in range(REPS)]
df = pd.DataFrame(Parallel(n_jobs=N_JOBS, backend="loky", inner_max_num_threads=1)(
delayed(_cell)(lab, fp, pr, r) for lab, fp, pr, r in jobs))
df.to_parquet(RUNS / "spec_point.parquet", index=False)
f = SimConfig(**SPEC_POINT).f
print(f"\n{'arm':>32} {'D-hat/D':>18} {'predicted':>10} {'consensus':>10}")
for lab, fp, pr in ARMS:
g = df[df.arm == lab]
pred = fixed_point_bias(f, pr) if fp else 1.0
print(f"{lab:>32} {g.mean_ratio.mean():10.5f}+-{g.mean_ratio.sem():.5f} "
f"{pred:10.5f} {('exact' if g.range_ratio.max() == 0 else 'SPREAD'):>10}")
print(f"\nfork rate {df.fork_rate.mean():.3f}, p_ref {df.p_ref.mean():.4f}, "
f"{REPS} replicates, k = 2160")
print(f"wrote {RUNS}/spec_point.parquet")
if __name__ == "__main__":
main()