Vote for your favorite SkillMD. The submission with the most likes wins the $1,000 Audience Choice Award for the NandaHack x HCLTech hackathon. Voting is open through September 25.Vote now →
mergedhumanPR #24Registry

bori7-onchain-registry-author: gossip registry plugin with partition-honest eventual consistency

[#06 registry-gossip-eventual-consistency](https://github.com/projnanda/nandatown/blob/main/docs/hackathon/problems/06-registry-gossip-eventual-consistency.md).

Author

Status
Merged
Merged on
Jun 19
Branch
hackathon/bori7-onchain-registry-author-gossip

Description

The pitch.

## Problem

[`#06 registry-gossip-eventual-consistency`](https://github.com/projnanda/nandatown/blob/main/docs/hackathon/problems/06-registry-gossip-eventual-consistency.md). The shared-dict `in_memory` plugin is operationally a lie under `failures.network_partition`: partitioned agents still discover each other through one dict. Zero PRs touched registry; this fills the wishlist's "gossip-based discovery" gap.

## Persona

**On-chain registry author** — the same engineer who shipped a linearisable, partition-fatal on-chain registry writes the eventually-consistent counterpart, and the diff foregrounds the trade-off: partition-honest local views (vs the on-chain version's strong consistency), bounded convergence (vs instant finality), LWW with `(version, publisher_id)` tags (vs the on-chain version's total order). Test emphasis matches: partition-tolerance + convergence bounds + adversarial replay.

## What's in the diff

| Path | Purpose |
|---|---|
| `packages/nest-plugins-reference/nest_plugins_reference/registry/gossip.py` | `GossipRegistry` plugin + `GossipNetwork` backplane + Lamport-style write tags |
| `packages/nest-plugins-reference/nest_plugins_reference/validators/` | `check_no_partition_view_leak` + `check_converged` — adversarial: FAILS by construction against `in_memory`, PASSES against gossip |
| `packages/nest-core/nest_core/scenarios_builtin/gossip_registry.py` | `GossipDriverAgent` + factory; per-agent registry instances via the `_agent_plugins` override channel |
| `scenarios/gossip_registry.yaml` + bundled copy | 21 agents (2 partition groups + bridge), 5% drop, deterministic under seeds 42 / 7 / 1337 |
| `packages/nest-core/nest_core/plugins.py` | `("registry", "gossip")` entry |
| `packages/nest-core/nest_core/scenarios.py` | `gossip_registry` built-in scenario registration |

## Verification

```bash
make ci-local
# ci-local: all 5 checks passed.
# 372 passed, 1 skipped, 1 deselected, 1 warning in 10.65s
# (baseline on main: 341 passed; this PR adds 31)

uv run pytest packages/nest-plugins-reference/tests/test_gossip_registry.py packages/nest-plugins-reference/tests/test_gossip_validators_and_scenario.py -v
# 31 tests, all green
```

Run the scenario directly:

```bash
uv run nest run gossip_registry
uv run nest inspect ./traces/gossip_registry.jsonl
```

## Reviewer notes worth surfacing

1. **Bridge vs heal interpretation.** The problem doc cites *both* "convergence requires a bridge" and "lookup must not return cards from the other partition" — in tension when a bridge exists. I model the bridge case (matching the simulator's static `partition_map` shape, which lists named groups and stays fixed for the run), and the adversarial leak check is exercised against `in_memory` and against a bridge-less partitioned topology — there it remains a genuine discriminator. Extending `FailureConfig` with `partition_heal_at_tick` would be a cleaner fit for the literal "heal" wording but would touch simulator core outside this layer's scope; the persona errs toward keeping the diff focused on the registry layer.
2. **K = 10 justification** (in `gossip.py` module docstring): `N=20, F=3` → `log_F(N) ≈ 3` rounds best case; 2× for 5% message drop ≈ 6; K=10 leaves safety margin for event-queue jitter.
3. **`TICK_REDUNDANCY = 5`.** The simulator's `failures.message_drop` also drops self-scheduled wake-ups, so a single drop kills an agent's tick chain. Each fire schedules 5 redundant ticks at staggered delays; chain-death probability per round drops to `drop_rate ** 5 ≈ 3e-7` at 5% drop. Each fire de-duplicates via `_last_round_at` so redundancy doesn't amplify gossip traffic.
4. **Determinism.** No wall-clock reads. Peer selection uses each agent's seeded `ctx.rng`. Same seed → byte-identical view trajectory (`test_same_seed_same_view_trajectory` + the parameterised seeds 42 / 7 / 1337 in the integration test).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Try it

Open PR on GitHubView diff

Checkout locally

git fetch origin pull/24/head:pr-24
git checkout pr-24