diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-06 23:01:36 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-06 23:01:36 +0200 |
| commit | 13ccc4a16c604f46ed10b6c5dbfbc8fdd7d008c0 (patch) | |
| tree | ecf819878b8f17596af5533e6845028680f1815d /packages/meshbay-node/src/meshbay_node/transport/wire.py | |
| parent | d6e1cc19a09df35988f6a90c226c94f2fdf6b209 (diff) | |
| download | meshbay-13ccc4a16c604f46ed10b6c5dbfbc8fdd7d008c0.tar.gz | |
fix: a root change reaches every client without a page reload
The directory table travelled on `index_sync` alone — a *full* index, which the
node only ever sends on request. Every ongoing change went out as an
`index_delta`, which carried files and nothing else. So the message that says
"something changed" was the one message that could not say a root had.
The acks hid it: `root_add_ack` and friends broadcast the new table to whoever
is connected, so the common cases looked right. What that could not cover was
the operator's own client, where the ack landed and was then overwritten — the
table calls `onRefreshIndex` after an add, that fetch returns the set from
*before* the node's reload (fire-and-forget, because a rescan is minutes on a
real library), and `applyIndex` writes it over what the ack had just delivered.
The new directory appeared for one paint and vanished.
Two halves. `index_delta` now carries the roots table, sealed with the rest and
identical to `index_sync`'s — additive, so a 1.0 client sees a field it does not
read. And the table no longer refreshes the index after a root change: the ack
gives it the new set immediately, and the delta the node pushes when the scan
finishes gives it again, along with the files.
The test that pins it uses an *eject* as its case, because an eject changes no
file at all — the entries freeze — so its delta is empty of additions,
deletions and updates. Without the table it says literally nothing, which is
how a library disappearing from under a group went unannounced to everyone but
whoever pressed the button.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011pvMdvLBG92jyhvD5pD6us
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/transport/wire.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/transport/wire.py | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/transport/wire.py b/packages/meshbay-node/src/meshbay_node/transport/wire.py index c683204..6986b01 100644 --- a/packages/meshbay-node/src/meshbay_node/transport/wire.py +++ b/packages/meshbay-node/src/meshbay_node/transport/wire.py @@ -89,13 +89,21 @@ def index_sync_message(index, roots: RootSet | None) -> dict: } -def index_delta_message(index, delta) -> dict: +def index_delta_message(index, delta, roots=None) -> dict: """ One `index_delta` — what changed since the last thing this node broadcast. Built here rather than inline in the daemon, which is where it lived and which made it the third place an index message was constructed: precisely the drift that produced two `index_sync` encodings and two `file_chunk` encodings before it. + + `roots` rides along (MNP 1.1, additive — a 1.0 client ignores it). It used + to travel on `index_sync` alone, which is a *full* index and therefore only + ever sent on request. So a root added, removed, ejected or plugged left + every connected client's directory table stale until somebody reloaded the + page: the delta that told them something had changed was the one message + that could not say what. It is a handful of dicts, bounded by the number of + directories a group has, and it is sealed with the rest. """ payload = { "base_version": delta.base_version, @@ -104,6 +112,8 @@ def index_delta_message(index, delta) -> dict: "deletions": list(delta.deletions), "updates": [index_entry_wire(e) for e in delta.updates], } + if roots is not None: + payload["roots"] = roots.describe() return { "type": MNP.INDEX_DELTA, "v": MNP_VERSION, |