1d99e7f9a9
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 <noreply@anthropic.com>
108 lines
4.5 KiB
Python
108 lines
4.5 KiB
Python
"""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()
|