Skip to content

sync: a node adopts only paths inside its own include from a peer - #98

Merged
myobie merged 1 commit into
mainfrom
fix/adopt-honours-the-receivers-include
Aug 30, 2026
Merged

sync: a node adopts only paths inside its own include from a peer#98
myobie merged 1 commit into
mainfrom
fix/adopt-honours-the-receivers-include

Conversation

@myobie

@myobie myobie commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Finding 8 of the 2026-08-29 review — the receive-side half of the defect whose delete side was finding 2 (already merged and deployed as #86).

The hole

adopt took every winning entry a peer sent, with no reference to this node's include. So a host with a broad include (or a mistaken ["**"]) had its machine-local files — pty/*.events.jsonl, sockets, lock files — adopted into every peer's manifest and relayed onward across the mesh. The README says "Positive includes are the safety boundary"; the code enforced that only on scan_folder, not on receive.

The fix

adopt_from_peer refuses a path outside this node's include: it never enters the manifest, never records into the change buffer, and so never crosses the wire to a third peer. The two wire sites use it (run_client's reply adopt, run_server's push adopt).

Kept distinct from loading a node's own state. load_node_and_observed still uses plain adopt, which keeps every path the node already held even outside a narrowed include — that record is the node's own, and dropping it would forget a file this machine still holds. The node's include is set from its entry config in load_node_and_observed and refreshed on every reload, so a narrowed or widened include takes effect immediately.

Behaviour change (why this wants care on merge timing)

  • Two peers whose includes differ no longer converge on the excluded paths. That is the point — machine-local files should not spread — but it means such an entry never reaches the digest-equal noop fast path while the includes differ. In a correct configuration (consistent includes for shared paths) nothing is excluded and convergence is unchanged.
  • Widening a receiver's include now re-adopts the newly-included paths from a peer on the next reconcile, rather than materialising them from a manifest it had already taken.

On the current fully-meshed fleet the relay hazard cannot fire (every host talks to every host directly), and the delete half (#86) is already deployed. So this is correctness/cleanliness for the mesh and a real boundary for any non-meshed or misconfigured topology. Given it changes wire/convergence semantics, it is worth landing after the 0.9 soak rather than into it.

Proof

  • adopt_from_peer_refuses_a_path_outside_the_include — red without the filter, green with it; a peer's out-of-scope path is not taken and is not offered from the change buffer.
  • adopt_from_peer_with_no_include_takes_everything — control: no include configured takes everything.
  • adopt_keeps_the_nodes_own_path_even_outside_a_narrowed_include — the local-load direction still keeps the node's own path.
  • a_path_outside_the_receivers_include_is_not_deleted now also asserts, over real iroh, that B's manifest present count is 1 (only the included path).

Full suite green locally on macOS.

Finding 8 of the 2026-08-29 review, the receive-side half; finding 2 was the
delete half. adopt took every winning entry a peer sent, whatever this node's
include said, so a host with a broad include had its machine-local files
adopted into every peer's manifest and relayed onward across the mesh. The
README always described includes as the boundary; the code enforced it only
on the scan.

adopt_from_peer refuses a path outside this node's include, so it never
enters the manifest and never crosses the wire to a third peer. The two wire
sites (run_client's reply adopt and run_server's push adopt) use it; loading
this node's OWN durable state still uses adopt, which keeps every path it
already held even outside a narrowed include, because that record is the
node's and not a peer's. The node's include is set from its entry config in
load_node_and_observed and refreshed on every reload.

Behaviour change: peers whose includes differ no longer converge on the
excluded paths, and widening a receiver's include re-adopts from a peer on
the next reconcile rather than materialising a path it had already taken.

Proof: adopt_from_peer_refuses_a_path_outside_the_include (red without the
filter) and adopt_keeps_the_nodes_own_path_even_outside_a_narrowed_include
pin the two directions; a_path_outside_the_receivers_include_is_not_deleted
now also asserts, over real iroh, that B's manifest holds only the included
path.
@myobie
myobie force-pushed the fix/adopt-honours-the-receivers-include branch from ef264ca to e86f3e6 Compare August 30, 2026 12:04
@myobie
myobie merged commit 65d6f24 into main Aug 30, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant