From 1d99e7f9a95b77b1f728806bcda8c476220b7905 Mon Sep 17 00:00:00 2001 From: leetcrypt Date: Tue, 21 Jul 2026 18:38:55 -0700 Subject: [PATCH] RQ2-P3: bridge-federated-pool mechanism instrument + synthetic tests + calibration gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build the funnelling-mechanism instrument for the RQ2-P3 follow-up: a new `bridge-federated-pool` topology drawing each circuit's bridge from a finite willing-bridge pool (size B) under Zipf willingness skew (alpha), so bridge concentration genuinely varies as a manipulated IV. Defensive measurement only: synthetic seeds, no engine, no traffic, no confirmatory record read. - assembler.py: add `bridge-federated-pool` branch + zipf_weights/weighted_draw helpers; existing lead `bridge-federated` branch left untouched and bit-reproducible (fresh bridge per seed). - battery.py: enumerate_rq2p3_cells() = B{2,4,8} x alpha{0,1,2} + anchor B=50, alpha=0 (separate fn; frozen 6-cell lead lattice unmutated). - analysis/rq2p3_calibration.py: DRY synthetic-only §7 calibration gate; no confirmatory data read. confirm_load_rq2.py/confirm.py/stats.py unchanged. - tests/test_sor_rq2p3_pool.py: 9 synthetic tests (helpers + pool reuse/variance + lead branch reproducibility). Calibration gate RAN: items 3 (monotonicity) & 4 (entropy) PASS; items 1 & 2 do NOT match their naive-funnel wording because the ratified posterior yields a MIX (rho>0 across the whole sweep incl anchor rho=+0.838; B=1 -> H=2.54 bits HIGH) -- the note-unique-bridge-artifact.md prediction, surfaced early. HARD HOLD: no confirmatory battery, no prereg freeze; NEEDS-OPERATOR banner raised for the §7 item-1/2 re-word decision. Lead prereg SHA f22331a72e... untouched; worktree-only. Co-Authored-By: Claude Opus 4.6 --- OVERSEER-STATUS.md | 16 ++ cmd_chat/sor/analysis/rq2p3_calibration.py | 175 +++++++++++++++++++++ cmd_chat/sor/assembler.py | 53 ++++++- cmd_chat/sor/battery.py | 34 ++++ tests/test_sor_rq2p3_pool.py | 107 +++++++++++++ 5 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 cmd_chat/sor/analysis/rq2p3_calibration.py create mode 100644 tests/test_sor_rq2p3_pool.py diff --git a/OVERSEER-STATUS.md b/OVERSEER-STATUS.md index 7b5de86..e965760 100644 --- a/OVERSEER-STATUS.md +++ b/OVERSEER-STATUS.md @@ -1,5 +1,18 @@ # OVERSEER-STATUS — sor-consent build agent +> **NEEDS-OPERATOR (2026-07-21, RQ2-P3 mechanism instrument):** the `bridge-federated-pool` +> instrument is BUILT + synthetic-tested (9 tests) + the §7 calibration gate was RUN. Items **3 +> (monotonicity) and 4 (entropy) PASS**; items **1 and 2 do NOT hold as their naive-funnel text is +> worded** — because the *ratified* posterior mechanically yields a **MIX** (ρ>0), not the naive +> funnel. Item-1 anchor B=50,α=0 gives ρ=**+0.838** (stdev 0.0198), NOT the ρ-undefined zero-variance +> degeneracy §7 expected; item-2 B=1 gives concentration c=1.0 (✓) but H=**2.54 bits HIGH** vs the +> fresh-bridge reference 0.0 bits, contradicting the "low H" gloss. Every ρ across the whole +> B∈{2,4,8}×α∈{0,1,2} sweep is ≥0 (0.00→0.838): a robust mix everywhere. This is exactly +> `docs/note-unique-bridge-artifact.md`'s prediction, surfaced early at calibration — NOT an +> instrument bug. **STOPPED per rail:** no confirmatory RQ2-P3 battery, no prereg freeze. Operator +> must decide: re-word `rq2p3-mechanism-prereg.md` §7 gate items 1–2 (naive→mechanical) before +> freezing, or rule otherwise. Lead prereg SHA f22331a72e… UNTOUCHED; worktree-only. + RQ2 RATIFIED (operator Andre, 2026-07-20, while blind) — observation-consistent-set + uniform-mass per-circuit posterior; docs/stage-05-rq2-posterior-clarification.md flipped PROPOSED→RATIFIED. Offline loader built + synthetic-tested. BLIND HOLD REMAINS: no real RQ2 result until the battery completes. @@ -66,3 +79,6 @@ RQ2 RATIFIED (operator Andre, 2026-07-20, while blind) — observation-consisten - 2026-07-20 SS5 ADVERSARIAL REVIEW DONE + committed: docs/stage-08-adversarial-review.md — self red-team of the filled paper vs stage06-results.json (no new stat, no raw-data touch, prereg untouched). PASS on: number fidelity (every abstract/§5 figure matches JSON to precision), Holm arithmetic (7,6,5,4; only RQ1-P1+RQ2-P1 survive), spin/over-claim (no-leak framing, honest-negative equal-prominence, lab-scope disclaimers), blinding integrity (§5-6 filled once post-seal), method-substitution (bit-faithful --verify). - 1 DEFECT FOUND + FIXED (prose only, ZERO numbers changed): RQ1-P1's below-chance AUC was wrongly attributed to "the bridge padding stream flattening" — but assembler.py sets padding_applied=(bridge=="on+padding"), so the no-pad RQ1-P1 arm carries NO cover stream. Corrected docs/stage-06-analysis.md + paper §5.2/§6 to state it's an unexplained pooled-correlator artifact, explicitly NOT padding. Point/CI/gate/Holm untouched. - STEPPING STONES COMPLETE: SS1 executor ✅ SS2 battery+freeze ✅ SS3 §6 pass ✅ SS4 paper fill ✅ SS5 red-team ✅. Honest double-null/negative lead paper ready for operator review. prereg SHA INTACT; worktree-only feat/sor-consent-relay. +- 2026-07-21 RQ2-P3 MECHANISM INSTRUMENT BUILT + committed: assembler.py `bridge-federated-pool` topology (finite willing-bridge pool size B under Zipf willingness skew α; per-circuit draw idx=weighted_draw(sha256("sor-bridge-pool|{seed}"), zipf_weights(B,α)) → bridge#{idx:02d}) + helpers `zipf_weights`/`weighted_draw`; existing lead `bridge-federated` branch UNTOUCHED (still fresh-bridge-per-seed, bit-reproducible). battery.enumerate_rq2p3_cells() = B∈{2,4,8}×α∈{0,1,2} + anchor B=50,α=0, tagged RQ2P3 (SEPARATE fn; frozen 6-cell lattice unmutated). analysis/rq2p3_calibration.py = DRY synthetic-only §7 gate (no confirmatory record read). confirm_load_rq2.py/confirm.py/stats.py UNCHANGED. +- CALIBRATION GATE RAN (§7, DRY): item3 monotonicity PASS (top-3 conc ↓ in B, ↑ in α), item4 entropy PASS (plug-in=log2N exact). item1 + item2 DO NOT match naive wording → MIX not funnel (see top-of-file NEEDS-OPERATOR): anchor ρ=+0.838, B=1 H=2.54 bits HIGH, all 10 sweep ρ≥0. Surfaced, not reconciled. Tests: tests/test_sor_rq2p3_pool.py 9 passed; full SOR suite 185 passed (lead bridge-federated fingerprint reproducible — no regression). +- HARD HOLD: no RQ2-P3 confirmatory battery, no `rq2p3-mechanism-prereg.md` freeze (§10 block still empty) — operator-gated on the item-1/2 re-word decision. Lead prereg SHA f22331a72e… INTACT; containment intact (synthetic-only, no engine/traffic); worktree-only. NEXT (operator-gated): RQ3 executor wiring, only after this ruling. diff --git a/cmd_chat/sor/analysis/rq2p3_calibration.py b/cmd_chat/sor/analysis/rq2p3_calibration.py new file mode 100644 index 0000000..3e98ee9 --- /dev/null +++ b/cmd_chat/sor/analysis/rq2p3_calibration.py @@ -0,0 +1,175 @@ +"""RQ2-P3 mechanism-instrument calibration gate (`rq2p3-mechanism-prereg.md` §7). + +DRY, SYNTHETIC-ONLY calibration of the new ``bridge-federated-pool`` topology: it +assembles circuits from harness-generated per-circuit seeds (NOT a confirmatory data +dir), then reports the four §7 gate items. **No confirmatory record is read** — this +is the same blind-safe discipline as the lead-paper loaders; the confirmatory battery +stays HARD-HELD until the prereg is frozen. + +Gate items (§7): + 1. Reproduce the lead degeneracy — ``B=50, alpha=0`` → ``c_i`` ≈ 1/C, near-constant, + Spearman ρ inconclusive. + 2. Extreme ``B=1`` — all circuits share one bridge → ``c=1.0`` (a degenerate + concentration extreme). NOTE: under the RATIFIED posterior a fully-shared bridge + *maximizes* the observation-consistent anonymity set, so realized H comes out + HIGH, not low — the mechanical "mix" the study exists to test. This is surfaced, + not silently reconciled with the naive "low H" gloss. + 3. Monotonicity — mean top-3 concentration decreases in B and increases in alpha. + 4. Entropy calibration (inherited) — plug-in entropy of N equiprobable senders is + exactly log2(N); Miller–Madow adds only the documented finite-N bias term. +""" + +from __future__ import annotations + +import hashlib +import json +import math +import statistics +import sys +from typing import Dict, List + +from cmd_chat.sor.analysis.confirm_load_rq2 import ( + bridge_concentration, + per_circuit_entropy, + top_k_bridge_concentration, +) +from cmd_chat.sor.analysis.stats import miller_madow_entropy_bits, spearman +from cmd_chat.sor.assembler import assemble +from cmd_chat.sor.battery import Cell, derive_seed, enumerate_rq2p3_cells + +R_DRY = 30 # runs/cell for the dry calibration (matches the prereg §6 R) +C_DRY = 50 # circuits/run (matches C) + + +def _run_circuit_seeds(cell_id: str, run_index: int, c: int = C_DRY) -> List[int]: + """Harness-side per-circuit seeds for the DRY pass (the confirmatory executor + persists real per_circuit_seeds; this is calibration only). Deterministic from + the frozen per-run seed rule so the calibration is reproducible.""" + run_seed = derive_seed(cell_id, run_index) + return [int.from_bytes(hashlib.sha256(f"{run_seed}|circ|{j}".encode()).digest()[:8], "big") + for j in range(c)] + + +def _assemble_run(cell: Cell, run_index: int, c: int = C_DRY): + return [assemble(cell, s) for s in _run_circuit_seeds(cell.cell_id, run_index, c)] + + +def _pool_cell(b: int, alpha: float) -> Cell: + return Cell("RQ2P3", f"RQ2P3/dry/B={b}/alpha={alpha}", + {"bridge": "off", "topology": "bridge-federated-pool", + "selector": "static", "pool_B": str(b), "pool_alpha": str(alpha)}, False) + + +def cell_report(cell: Cell, r: int = R_DRY, c: int = C_DRY) -> Dict: + """Per-cell dry report: mean top-3 concentration over runs, pooled per-circuit + (c_i, H_i) Spearman ρ, and the concentration spread.""" + per_run_top3: List[float] = [] + per_run_mean_h: List[float] = [] + conc_all: List[float] = [] + h_all: List[float] = [] + for ri in range(r): + specs = _assemble_run(cell, ri, c) + per_run_top3.append(top_k_bridge_concentration(specs, k=3)) + ent = per_circuit_entropy(specs) + per_run_mean_h.append(statistics.fmean(ent)) + for ci, hi in zip(bridge_concentration(specs), ent): + if ci is not None: + conc_all.append(ci) + h_all.append(hi) + b = int(cell.factors["pool_B"]) + alpha = float(cell.factors["pool_alpha"]) + return { + "B": b, + "alpha": alpha, + "mean_top3_concentration": statistics.fmean(per_run_top3), + "concentration_stdev": statistics.pstdev(conc_all) if conc_all else 0.0, + "mean_entropy_bits": statistics.fmean(per_run_mean_h), + "spearman_rho_conc_vs_H": spearman(conc_all, h_all), + "n_bridged_circuits": len(conc_all), + } + + +def calibration_gate(r: int = R_DRY, c: int = C_DRY) -> Dict: + """Run all four §7 gate items on the DRY pass and return a report dict.""" + sweep = [cr for cr in (cell_report(cell, r, c) for cell in enumerate_rq2p3_cells())] + grid = {(cr["B"], cr["alpha"]): cr for cr in sweep} + + # Item 1 — anchor B=50, alpha=0 reproduces the lead degeneracy. + anchor = grid[(50, 0.0)] + item1_pass = anchor["concentration_stdev"] < 1e-3 and abs(anchor["spearman_rho_conc_vs_H"]) < 0.05 + + # Item 2 — extreme B=1: all circuits share one bridge (degenerate concentration). + ext = cell_report(_pool_cell(1, 0.0), r, c) + lead_like = cell_report(_pool_cell(1_000_000, 0.0), r, c) # huge pool ≈ fresh bridge/circuit + item2_conc_ok = abs(ext["mean_top3_concentration"] - 1.0) < 1e-9 + # The naive gate text says "low H"; the ratified posterior yields HIGH H. Surface it. + item2_entropy_direction = "HIGH (mechanical mix)" if ext["mean_entropy_bits"] > lead_like["mean_entropy_bits"] else "low" + item2_matches_naive_low_H = ext["mean_entropy_bits"] < lead_like["mean_entropy_bits"] + + # Item 3 — monotonicity: mean top-3 concentration decreasing in B, increasing in alpha. + dec_in_B = all( + grid[(2, a)]["mean_top3_concentration"] >= grid[(4, a)]["mean_top3_concentration"] >= grid[(8, a)]["mean_top3_concentration"] + for a in (0.0, 1.0, 2.0) + ) + inc_in_alpha = all( + grid[(b, 0.0)]["mean_top3_concentration"] <= grid[(b, 1.0)]["mean_top3_concentration"] <= grid[(b, 2.0)]["mean_top3_concentration"] + for b in (2, 4, 8) + ) + item3_pass = dec_in_B and inc_in_alpha + + # Item 4 — entropy calibration (inherited): plug-in H of N equiprobable = log2(N) exactly. + entropy_checks = [] + item4_pass = True + for n in (2, 4, 8, 16, 50): + mm = miller_madow_entropy_bits([1] * n) + bias = (n - 1) / (2.0 * n * math.log(2.0)) + plugin = mm - bias + ok = abs(plugin - math.log2(n)) < 1e-9 + item4_pass = item4_pass and ok + entropy_checks.append({"N": n, "plugin_bits": plugin, "log2N": math.log2(n), + "miller_madow_bits": mm, "plugin_equals_log2N": ok}) + + return { + "schema": "sor-rq2p3-calibration/1", + "dry_only": True, + "no_confirmatory_data_read": True, + "R": r, "C": c, + "sweep": sweep, + "gate": { + "item1_reproduce_lead_degeneracy": { + "anchor_B50_alpha0": anchor, + "pass": item1_pass, + }, + "item2_extreme_B1": { + "mean_top3_concentration": ext["mean_top3_concentration"], + "mean_entropy_bits": ext["mean_entropy_bits"], + "fresh_bridge_reference_mean_entropy_bits": lead_like["mean_entropy_bits"], + "concentration_degenerate_c_eq_1": item2_conc_ok, + "entropy_direction_vs_naive": item2_entropy_direction, + "matches_naive_low_H_expectation": item2_matches_naive_low_H, + "NEEDS_OPERATOR": not item2_matches_naive_low_H, + "note": ( + "Concentration extreme is as specified (c=1.0). But the ratified " + "posterior makes a fully-shared bridge MAXIMIZE the anonymity set, so " + "realized H is HIGH, contradicting the §7 gate-item-2 'low H' gloss. " + "This is exactly the mechanical 'mix' (ρ>0) the study exists to test " + "(see note-unique-bridge-artifact.md), surfaced early at calibration. " + "Not silently reconciled: flagged for the operator's freeze decision." + ), + }, + "item3_monotonicity": { + "decreasing_in_B": dec_in_B, + "increasing_in_alpha": inc_in_alpha, + "pass": item3_pass, + }, + "item4_entropy_calibration": { + "checks": entropy_checks, + "pass": item4_pass, + }, + }, + } + + +if __name__ == "__main__": + print(json.dumps(calibration_gate(), indent=2, sort_keys=True)) + sys.exit(0) diff --git a/cmd_chat/sor/assembler.py b/cmd_chat/sor/assembler.py index 227f788..7afa307 100644 --- a/cmd_chat/sor/assembler.py +++ b/cmd_chat/sor/assembler.py @@ -132,6 +132,36 @@ def _bridge_label(seed: int) -> str: return f"bridge#{hashlib.sha256(f'sor-bridge|{seed}'.encode()).hexdigest()[:8]}" +def zipf_weights(pool_size: int, alpha: float) -> List[float]: + """Deterministic Zipf willingness weights over a finite willing-bridge POOL of + ``pool_size`` bridges: rank ``r`` (1..B) gets mass ∝ ``1/r**alpha``, normalized to + sum 1. ``alpha = 0`` → uniform willingness; larger ``alpha`` → heavier skew toward + the most-willing bridges (higher realized concentration). Pure function of + ``(pool_size, alpha)`` — both cell-level factors — so the willingness profile is + fixed within a run (RQ2-P3 mechanism prereg §3).""" + if pool_size < 1: + raise ValueError(f"pool_size must be >= 1, got {pool_size}") + raw = [1.0 / (r ** alpha) for r in range(1, pool_size + 1)] + total = sum(raw) + return [w / total for w in raw] + + +def weighted_draw(digest_hex: str, weights: List[float]) -> int: + """Deterministic index in ``[0, len(weights))`` by CDF inversion of a SHA-256 + hex digest: the first 8 bytes map to ``u ∈ [0, 1)`` and we return the first bin + whose cumulative weight exceeds ``u``. Deterministic from ``digest_hex`` (a + per-circuit hash), so a circuit's willing bridge is reproducible from its seed.""" + if not weights: + raise ValueError("weights must be non-empty") + u = int(digest_hex[:16], 16) / float(1 << 64) + cum = 0.0 + for i, w in enumerate(weights): + cum += w + if u < cum: + return i + return len(weights) - 1 + + def _house_nodes(seed: int, pool: int, take: int, house: str, salt: int = 0) -> List[str]: idx = select_path(SorRng(seed ^ salt), pool, take) return [f"{house}#{i}" for i in idx] @@ -201,6 +231,27 @@ def assemble( ] houses = (HOUSES[0], HOUSES[1]) bridge_present = True + elif topo == "bridge-federated-pool": + # RQ2-P3 mechanism instrument (rq2p3-mechanism-prereg.md §3): identical + # to bridge-federated EXCEPT the willing bridge is drawn from a FINITE + # shared pool of size B under a fixed Zipf willingness (skew alpha), so + # circuits genuinely REUSE bridges and top-3 concentration varies. The + # existing bridge-federated branch above is left untouched (lead cells + # stay bit-reproducible). + pool_b = int(cell.factors["pool_B"]) + pool_alpha = float(cell.factors["pool_alpha"]) + a = _house_nodes(seed, house_size, 1, HOUSES[0], salt=0)[0] + b = _house_nodes(seed, house_size, 1, HOUSES[1], salt=0xB)[0] + weights = zipf_weights(pool_b, pool_alpha) + digest = hashlib.sha256(f"sor-bridge-pool|{seed}".encode()).hexdigest() + idx = weighted_draw(digest, weights) + hop_specs = [ + HopSpec(0, "entry", HOUSES[0], a, False), + HopSpec(1, "bridge", "bridge", f"bridge#{idx:02d}", True), + HopSpec(2, "exit", HOUSES[1], b, False), + ] + houses = (HOUSES[0], HOUSES[1]) + bridge_present = True elif topo == "directory-federated": directory = _build_directory(seed, house_size, n_houses) path = directory.select_federated_path(seed, hops=hops, min_houses=2) @@ -217,7 +268,7 @@ def assemble( matched_n=matched_n, houses=houses, hops=tuple(hop_specs), ) # Federated cells must genuinely span ≥ 2 houses (split-knowledge, RQ2). - if topo in ("bridge-federated", "directory-federated") and spec.span_houses() < 2: + if topo in ("bridge-federated", "bridge-federated-pool", "directory-federated") and spec.span_houses() < 2: raise ValueError(f"assembler: {cell.cell_id} failed the >=2-house span") return spec diff --git a/cmd_chat/sor/battery.py b/cmd_chat/sor/battery.py index 95f3062..d7279c7 100644 --- a/cmd_chat/sor/battery.py +++ b/cmd_chat/sor/battery.py @@ -92,6 +92,40 @@ def enumerate_cells() -> List[Cell]: return cells +def enumerate_rq2p3_cells() -> List[Cell]: + """The RQ2-P3 funnelling-mechanism sweep cells (`rq2p3-mechanism-prereg.md` §4), + kept **separate** from the frozen lead lattice: `enumerate_cells()` above is left + byte-identical so every lead-pipeline caller (`plan_runs`, `battery_schedule`, + `assembler_dry_check`, `collect_rq2_p1_arms`) stays bit-reproducible. + + These use the new `bridge-federated-pool` topology (finite willing-bridge pool of + size ``B`` under a Zipf willingness skew ``alpha``) so concentration genuinely + varies. Tagged ``rq = "RQ2P3"`` so they are distinct from the frozen RQ1/RQ2 + cells and are skipped by the lead RQ2 collectors (which filter ``rq == "RQ2"``). + + 9 sweep cells: ``B ∈ {2,4,8} × alpha ∈ {0, 1.0, 2.0}``, plus the ``B=50, alpha=0`` + **calibration anchor** that reproduces the lead RQ2-P3 degeneracy (§7 gate item 1). + """ + cells: List[Cell] = [] + for b in (2, 4, 8): + for alpha in (0.0, 1.0, 2.0): + cells.append(Cell( + "RQ2P3", + f"RQ2P3/topo=bridge-federated-pool/selector=static/B={b}/alpha={alpha}", + {"bridge": "off", "topology": "bridge-federated-pool", + "selector": "static", "pool_B": str(b), "pool_alpha": str(alpha)}, + False, + )) + cells.append(Cell( + "RQ2P3", + "RQ2P3/topo=bridge-federated-pool/selector=static/B=50/alpha=0.0", + {"bridge": "off", "topology": "bridge-federated-pool", + "selector": "static", "pool_B": "50", "pool_alpha": "0.0"}, + False, + )) + return cells + + def declared_na_cells() -> List[Cell]: """N/A cells declared at the design (not run, not dropped ad hoc) — padding is only defined for bridge-on, so bridge-off+padding is N/A (§2).""" diff --git a/tests/test_sor_rq2p3_pool.py b/tests/test_sor_rq2p3_pool.py new file mode 100644 index 0000000..883834e --- /dev/null +++ b/tests/test_sor_rq2p3_pool.py @@ -0,0 +1,107 @@ +"""RQ2-P3 mechanism instrument — the willing-bridge POOL topology, on SYNTHETIC +seeds ONLY (`rq2p3-mechanism-prereg.md` §3). No confirmatory record is read. + +Pins: (a) the pool helpers `zipf_weights` / `weighted_draw` are deterministic and +well-formed; (b) the new `bridge-federated-pool` branch draws from a finite pool so +circuits genuinely REUSE bridges (label collisions → concentration variance), while +still spanning ≥2 houses and staying isolation-gated; (c) the existing lead +`bridge-federated` branch is left bit-reproducible (fresh bridge per seed, unchanged). +""" + +import hashlib + +from cmd_chat.sor.analysis.confirm_load_rq2 import bridge_concentration, bridge_label +from cmd_chat.sor.assembler import assemble, weighted_draw, zipf_weights +from cmd_chat.sor.battery import Cell, derive_seed + + +def _pool_cell(b, alpha): + return Cell("RQ2P3", f"RQ2P3/B={b}/alpha={alpha}", + {"bridge": "off", "topology": "bridge-federated-pool", + "selector": "static", "pool_B": str(b), "pool_alpha": str(alpha)}, False) + + +def _fed_cell(): + return Cell("RQ2", "RQ2/bridge=off/selector=static/topo=bridge-federated", + {"bridge": "off", "topology": "bridge-federated", "selector": "static"}, False) + + +def _circuit_seeds(cell_id, n=50): + run_seed = derive_seed(cell_id, 0) + return [int.from_bytes(hashlib.sha256(f"{run_seed}|circ|{j}".encode()).digest()[:8], "big") + for j in range(n)] + + +# --- pool helpers ---------------------------------------------------------- # +def test_zipf_weights_normalized_and_uniform_at_alpha0(): + w = zipf_weights(8, 0.0) + assert len(w) == 8 + assert abs(sum(w) - 1.0) < 1e-12 + assert all(abs(x - 1.0 / 8) < 1e-12 for x in w) # alpha=0 → uniform + + +def test_zipf_weights_skew_monotone_decreasing(): + w = zipf_weights(8, 2.0) + assert abs(sum(w) - 1.0) < 1e-12 + assert all(w[i] > w[i + 1] for i in range(len(w) - 1)) # rank-1 heaviest + assert w[0] > zipf_weights(8, 0.0)[0] # skew concentrates mass on top bridge + + +def test_weighted_draw_deterministic_and_respects_extreme_skew(): + d = hashlib.sha256(b"x").hexdigest() + assert weighted_draw(d, [0.25, 0.25, 0.25, 0.25]) == weighted_draw(d, [0.25, 0.25, 0.25, 0.25]) + # all mass on bin 0 → always bin 0, whatever the hash + for s in (b"a", b"b", b"c", b"zzz"): + assert weighted_draw(hashlib.sha256(s).hexdigest(), [1.0, 0.0, 0.0]) == 0 + + +# --- the pool topology ----------------------------------------------------- # +def test_pool_reuses_bridges_and_labels_stay_in_range(): + cell = _pool_cell(4, 0.0) + specs = [assemble(cell, s) for s in _circuit_seeds(cell.cell_id)] + labels = {bridge_label(s) for s in specs} + # B=4 pool over 50 circuits → far fewer distinct bridges than circuits (reuse), + # and every label is one of the B pool slots. + assert labels <= {f"bridge#{i:02d}" for i in range(4)} + assert 1 < len(labels) <= 4 + assert len(labels) < len(specs) + + +def test_pool_produces_concentration_variance_unlike_fresh_bridge(): + cell = _pool_cell(4, 1.0) + specs = [assemble(cell, s) for s in _circuit_seeds(cell.cell_id)] + conc = [c for c in bridge_concentration(specs) if c is not None] + assert len(conc) == len(specs) + assert max(conc) > min(conc) # genuine variance (the fresh-bridge instrument had none) + + +def test_pool_spans_two_houses_and_is_isolation_gated(): + cell = _pool_cell(8, 2.0) + spec = assemble(cell, derive_seed(cell.cell_id, 0)) + assert spec.span_houses() >= 2 + assert spec.isolation_gated() + assert spec.bridge_present and not spec.padding_applied + assert any(h.is_bridge for h in spec.hops) + + +def test_pool_assembly_is_deterministic(): + cell = _pool_cell(4, 1.0) + s = derive_seed(cell.cell_id, 0) + assert assemble(cell, s).fingerprint() == assemble(cell, s).fingerprint() + + +# --- lead bridge-federated branch untouched (bit-reproducible) ------------- # +def test_lead_bridge_federated_still_fresh_bridge_per_seed(): + cell = _fed_cell() + seeds = _circuit_seeds(cell.cell_id) + specs = [assemble(cell, s) for s in seeds] + labels = [bridge_label(s) for s in specs] + # fresh bridge per seed → all-distinct labels (the lead degeneracy), NOT pool slots + assert len(set(labels)) == len(labels) + assert all(not lbl.startswith("bridge#00") or len(lbl) > 9 for lbl in labels) + + +def test_lead_bridge_federated_fingerprint_reproducible(): + cell = _fed_cell() + s = derive_seed(cell.cell_id, 0) + assert assemble(cell, s).fingerprint() == assemble(cell, s).fingerprint()