From a16284ebc5915c4b13df3e552c03377c6ffd1fa5 Mon Sep 17 00:00:00 2001 From: Marcin Pawlowski Date: Fri, 7 Aug 2026 18:34:16 +0200 Subject: [PATCH] The uncle cap rule survives the anchor change; the window floor does not Second half of the re-measurement. Sizing U is unaffected: the smallest cap reaching the 0.98 bar is identical under both anchors at every load tested -- U=1 at rho 0.27 and 0.47, U=2 at 0.87, and neither clears at rho=1.27, which is past the operating point the recipe permits. U = ceil(rho)+1 carries over verbatim. At that cap the residual cost stays inside the design regime: -0.003 at rho 0.47 and 0.87, growing to -0.009 only at 1.27. So the anchor's cost lives in the WINDOW, not the cap, which is what the mechanism predicts -- the parent gap lengthens the queue's deadline without changing how fast it drains. Net effect on the recipe: U unchanged, W floor up one to two block-intervals, W = 10 still clearing at the deployed point and W = 12 restoring today's margin at heavier delay. Both sweeps are committed configs and their data archived, so the re-baselining is reproducible rather than a one-off. Co-Authored-By: Claude Fable 5 --- reports/tsi/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/reports/tsi/README.md b/reports/tsi/README.md index ec839b8..cc4a0f1 100644 --- a/reports/tsi/README.md +++ b/reports/tsi/README.md @@ -813,6 +813,8 @@ That measurement holds the cap slack, though, which hides the window. Isolating The floor rises by one to two block-intervals, which is what the ~one-block-interval-longer parent gap predicts. Two consequences for the sizing rules. At the deployed operating point nothing changes: the knee moves 5 → 6 and `W = 10` still clears with margin. At the heavier design point the margin behind `W = 10` narrows from 1.67× to 1.25×, so **a deployment adopting the parent anchor should size `W` against the parent gap** — `W = 12` restores the old margin, and the spec's `⌊0.6·k⌋` bound permits it without further change. The `δ_max` = 16 row is `U`-limited rather than window-limited (`ρ ≈ 0.87` against `U = 1`, below the recommended cap), so it measures the interaction of an under-provisioned cap with a tighter window rather than the window alone. +**The uncle cap rule is unchanged.** Sizing `U` is the other half of the recipe, and it is not affected: the smallest cap reaching the 0.98 bar is identical under both anchors at every load tested (`configs/window-uncles-anchor.yaml`, `W` = 10 held slack) — `U` = 1 at `ρ` = 0.27 and 0.47, `U` = 2 at 0.87, and neither anchor clears at `ρ` = 1.27, which is past the operating point the recipe permits anyway. `U = ⌈ρ⌉ + 1` therefore carries over verbatim. At that recommended cap the residual cost is small and stays inside the design regime: `−0.003` at `ρ` = 0.47 and 0.87, growing to `−0.009` only at `ρ` = 1.27. The anchor's cost lives in the window, not in the cap. + **One further observation, and it sharpens the case.** At `δ_max` = 16 the *honest* uncle-anchored arm already reaches **315 slots** — past its own `w_u` = 300. Under the current rule `w_u` is not a bound on how far back validation reaches even with no adversary present; under the parent rule the same cell is 296. The parameter only becomes a state-retention bound once it is anchored to the parent. ![Fig 38 — anchoring the reference window to the uncle's parent rather than the uncle: honest recovery is unchanged across the delay range (left), while a 30 % adversary's reach into historical chain state falls from the epoch boundary to the window itself (right, log scale).](report-figures/fig38_uncle_parent_window.png) @@ -1018,6 +1020,7 @@ Sweep studies are committed configs, run with `make ` (writes a dated `run | **uncle cap under a private chain** (`U` × `W` × `α` against the SM1 engine adversary, plus the structural/queue decomposition of the honest orphans) | `scripts/selfish_uncle_margin.py` (`adversary_strategy: selfish`); `runs/selfish_uncle_margin{,_decomp}.parquet` | [§6.8](#s6-8) | | **profit/deflation frontier** (how far a *paid* adversary can deflate `D̂`; the deflation-optimal MDP) | `scripts/deflation_frontier.py` (`selfish_mdp.deflation_frontier`, `.deflation_optimal_stats`); fig37 | [§6.6](#s6-6) | | **uncle- vs parent-anchored reference window** (honest recovery cost, and an adversary's reach into historical state) | `scripts/uncle_parent_window.py` (`uncle_window_anchor`, `adversary_strategy: deep_parent`); `runs/uncle_parent_window{,_effort}.parquet`; fig38 | [§6.12](#s6-12) | +| **the sizing rules re-measured under both anchors** (the `W` floor at `U` = 1; the `U` rule at `W` = 10) | `configs/absorption-window-anchor.yaml`, `configs/window-uncles-anchor.yaml` | [§3.4](#s3-4), [§6.12](#s6-12) | | **the deployed operating point** (`δ_max` = 4 from the spec's Blend profile; the three `f`-precision arms) | `scripts/spec_point.py` (`f_precision`); `runs/spec_point.parquet` | [§2.2](#s2-2), [§8.5](#s8-5), [Appendix A](#sA) | | **per-recipient delay variance** (jitter 0–8 slots × `U`, both referencing models, exact oracle) | `scripts/spec_jitter.py`, `configs/spec-point-jitter.yaml`; `runs/spec_jitter.parquet` | [§6.1](#s6-1), [§8.3](#s8-3) item 15 | | **the spec point at scale and by window** (`N` = 5000; `W_abs` sweep at `δ_max` = 4) | `configs/spec-point-n5000.yaml` (run twice, `--old`), `configs/spec-point-window.yaml` | [§3.4](#s3-4), [§8.5](#s8-5) |