in reviewhumanPR #190Registry
cover gossip registry partition honesty against the real simulator (problem 06)
<html>
Author
@ang101
github profile →- Status
- In review
- Opened on
- Jul 11
- Branch
- hackathon/ang101-gossip-partition-leak-coverage
Description
The pitch.
<html>
<p><strong>Title:</strong> <code>[Hackathon] ang101: cover gossip registry partition honesty against the real simulator (problem 06)</code></p>
<p><strong>Body:</strong></p>
<h2>Problem</h2>
<p><code>check_no_partition_view_leak</code> (<code>packages/nest-plugins-reference/nest_plugins_reference/validators/gossip_validators.py</code>) is the adversarial validator that should catch a <code>GossipRegistry</code> agent leaking a card straight across a network partition instead of only relaying it via a bridge. It has never actually been run against a real partition:</p>
<ul>
<li>Unit tests in this file and in <code>test_gossip_registry.py::test_partition_without_bridge_does_not_leak</code> all use a hand-rolled <code>_FakeNetwork</code>/<code>drop()</code> callable — never <code>nest_core.sim.simulator</code>'s real <code>_should_drop</code> partition logic.</li>
<li>The one test that <em>does</em> boot the real <code>Simulator</code> under a real partition (<code>test_scenario_converges_via_bridge_under_partition</code>, driving <code>scenarios/gossip_registry.yaml</code> via <code>ScenarioRunner</code>) only asserts <code>check_converged(...)</code> on the final state at end-of-run. It never calls <code>check_no_partition_view_leak</code> against a real mid-run snapshot.</li>
</ul>
<p>Net effect: a regression in <code>GossipRegistry</code> that leaked cross-group data through some other path — e.g. consulting a cached/shared view instead of only state that legitimately gossiped in — would pass the full test suite undetected.</p>
<h2>Fix</h2>
<p>Added <code>test_scenario_honors_partition_before_bridge_relay</code> (parametrized over seeds <code>42, 7, 1337</code>, matching this file's existing convention):</p>
<ol>
<li>Loads <code>scenarios/gossip_registry.yaml</code> via <code>ScenarioConfig.from_yaml</code>, overrides <code>duration</code> to <code>"ticks: 200"</code>.</li>
<li>Runs it through the real <code>ScenarioRunner</code>/<code>Simulator</code> (<code>asyncio.run(runner.run())</code>) — identical code path to the full-length test, just truncated.</li>
<li>Reads <code>runner.resolved_plugins["_gossip_registries"]</code> (the real per-agent <code>GossipRegistry</code> instances the scenario factory stashes there) and calls <code>.view_snapshot()</code> on each — the exact production method (<code>gossip.py:329</code>), not a mock.</li>
<li>Asserts at least one agent's view exceeds size 1 (proves real gossip propagated, not just each agent's own <code>on_start</code> self-registration — guards against the test being accidentally vacuous).</li>
<li>Calls <code>check_no_partition_view_leak(views=..., partition_groups=[peer_a[0..9], peer_b[0..9]], bridge_agents={AgentId("bridge-0")})</code> and asserts it passes.</li>
</ol>
<h3>Why 200 ticks specifically</h3>
<p>The scenario's partition never heals (<code>scenarios/gossip_registry.yaml</code> sets <code>network_partition.groups</code> with no <code>partition_heal_at_tick</code>), so any point before the bridge relays a card across groups is a valid "mid-partition, still honest" snapshot to check. But <code>duration: "ticks: N"</code> caps <strong>event count</strong>, not wall-clock time (<code>Simulator.run</code>'s <code>max_ticks</code> increments once per popped queue event), and <code>gossip_interval: 50</code> plus per-agent seeded RNG fanout selection makes event-to-round timing seed-dependent — so N had to be found empirically rather than derived:</p>
N | Behavior
-- | --
≤100 | Every agent's view size = 1 (only self-registration; first gossip round hasn't fired) — vacuous
200–250 | View sizes 1–4, real intra-group propagation, passes on all 3 required seeds
300 | Seed 42 starts legitimately failing — bridge has relayed a card cross-group by then
500–1000 | All seeds fail — full mesh convergence via bridge, exactly as intended by design
<p>200 was chosen for comfortable margin on both sides.</p>
<h2>Verification</h2>
<ul>
<
…Try it
Open PR on GitHubView diffCheckout locally
git fetch origin pull/190/head:pr-190
git checkout pr-190