Foundation work for cross-node DM mailbox replication. Adds the network
rule that makes the replication safe to ship next, plus the primitives
the outbound replication PR will call.
The rule
--------
A single sender can have at most N UNACKED messages parked in a single
recipient's mailbox at any one time. Default N=2, tunable via
``MESH_DM_PENDING_PER_SENDER_LIMIT``. Once the recipient pulls (acks) a
message, the sender's quota for that (sender, recipient) pair frees up.
Network rule, not local rule
----------------------------
The cap is enforced TWICE:
1. ``DMRelay.deposit(...)`` — local check on the sender's own node.
Refuses to spool the (N+1)th message before it can be replicated.
2. ``DMRelay.accept_replica(...)`` — replication-acceptance check on
every receiving peer. Refuses to accept an inbound replica that
would put the local mailbox over the cap.
The second half is what makes the rule a NETWORK rule. A hostile sender
could patch out the deposit check on their own relay and continue to
spool extras locally — but those extras can never propagate, because
every honest peer enforces the same cap on the way in. A recipient who
polls from honest peers therefore never sees more than N pending from
any one sender, regardless of how many spam attempts the hostile
sender's relay accepted.
New API surface on ``DMRelay``
------------------------------
_per_sender_pending_limit() — reads MESH_DM_PENDING_PER_SENDER_LIMIT
_per_sender_pending_count(...) — counts unacked from a sender for a mailbox
accept_replica(envelope=...) — peer-push receive entry point
envelope_for_replication(...) — helper to extract a wire-form envelope
``accept_replica`` is idempotent on duplicate ``msg_id`` (replication
round-trips and multi-path delivery don't double-spool).
``envelope_for_replication`` exposes the exact shape ``accept_replica``
expects, so the follow-up PR (outbound replication wiring) just has to
fetch the envelope and POST it to authenticated peer URLs with the
existing per-peer HMAC pattern from #256.
Why this is PR-1 of two
-----------------------
The full cross-node mailbox replication needs three pieces:
A. cap enforcement on deposit (in this PR)
B. cap enforcement on replica acceptance (in this PR)
C. outbound: push envelope to MESH_RELAY_PEERS after deposit (NEXT PR)
(A) + (B) shipped together close the cap-bypass attack surface BEFORE
(C) introduces the actual cross-node propagation. Shipping them in the
other order would briefly let extras propagate during the window between
"outbound push lands" and "accept_replica cap lands."
Tests
-----
backend/tests/test_dm_relay_per_sender_cap.py — 14 tests:
TestDepositCap:
- first 2 deposits succeed (UX baseline)
- 3rd from same sender rejected with friendly message
- different senders have independent quotas
- different recipients have independent quotas
- ack frees the quota (after recipient pulls, sender can deposit again)
- cap is env-tunable
TestAcceptReplicaCap:
- replica accepted under cap
- idempotent on duplicate msg_id (no double-spool, no rejection)
- rejected at cap with structured ``cap_violation`` marker so
sender's relay can stop retrying
- per-sender, not per-mailbox: different sender_block_ref passes
even when another sender at the same mailbox is capped
- malformed envelope shapes rejected without crash
TestEnvelopeForReplication:
- returns the envelope for stored messages
- returns None for unknown msg_id
- round-trips through accept_replica end-to-end (proves the wire
shape matches across the two sides)
Ship the v0.9.79 runtime refresh with transport lane isolation, Infonet secure-message address management, MeshChat MQTT controls, selected asset trail behavior, telemetry panel refinements, onboarding updates, and desktop/package metadata alignment.
Also ignore local graphify work products so analysis folders do not leak into future commits.
Gate messages now propagate via the Infonet hashchain as encrypted blobs — every node syncs them
through normal chain sync while only Gate members with MLS keys can decrypt. Added mesh reputation
system, peer push workers, voluntary Wormhole opt-in for node participation, fork recovery,
killwormhole scripts, obfuscated terminology, and hardened the self-updater to protect encryption
keys and chain state during updates.
New features: Shodan search, train tracking, Sentinel Hub imagery, 8 new intelligence layers,
CCTV expansion to 11,000+ cameras across 6 countries, Mesh Terminal CLI, prediction markets,
desktop-shell scaffold, and comprehensive mesh test suite (215 frontend + backend tests passing).
Community contributors: @wa1id, @AlborzNazari, @adust09, @Xpirix, @imqdcr, @csysp, @suranyami,
@chr0n1x, @johan-martensson, @singularfailure, @smithbh, @OrfeoTerkuci, @deuza, @tm-const,
@Elhard1, @ttulttul