aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-16 10:41:17 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-16 10:41:17 +0200
commit595d316f18576356182d81923b28b861bbaec2cc (patch)
tree0f8cc131891d2997ed0b4318c209e0b1871b131b /CLAUDE.md
parent9236ffdb295301f8cd61ad34689f84cf685d676e (diff)
downloadmeshbay-595d316f18576356182d81923b28b861bbaec2cc.tar.gz
docs: receiver-side SCTP rules, session gating on reconnect, processes default
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md41
1 files changed, 41 insertions, 0 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 5048488..dfcb0ed 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -761,6 +761,47 @@ do. Read them before writing anything that touches the same mechanism.
socket buffer gave 19.5 MB/s (`udp_buffer.py`); it needs
`net.core.rmem_max` raised on a default machine
+- **A transfer capped with a core busy: profile that process before tuning
+ the network.** The command-line client downloaded at 19 MB/s on loopback.
+ Its 4 MB receive buffer removed 3245 kernel drops and changed nothing else;
+ `top` then showed the client, not the node, at 100 %, and cProfile (a
+ wrapper script as `MESHBAY_CLI_E2E_BIN`, the e2e harness does the rest) put
+ two thirds of its time in aiortc's `InboundStream.pop_messages`: 153 million
+ steps for 400 MB, the reassembly walked from its start after every fragment.
+ Next, a SACK per packet cost the node more than sending. Both fixed in
+ `sctp_fix.py`: 39 MB/s, the node at 49. No amount of reading our code finds
+ a quadratic loop in a dependency; one profile does
+
+- **A default of "off" ships a feature nobody has.** `connection_processes`
+ defaulted to 1, which starts no process: the multi-core path was measured at
+ 131 MB/s and reached by no node whose operator had not found the setting, so
+ on Windows a download over eight lanes landed on the node's one core and ran
+ at the speed of one connection. Worse, the Node page saved **every** setting
+ on each Save, so any operator who changed one thing had pinned all the others
+ at that day's defaults, in the roster and in `node.toml`. It sends only what
+ changed now, and `init` leaves the line commented. A test node that saved
+ its settings before this keeps `connection_processes = 1` until it is set
+ again on the Node page
+
+- **A reconnect let every message through, not just its handshake.**
+ `_inReconnectAttempt` opened `_sendAndWait` to all callers so the handshake
+ would not wait on itself; a chunk retry landing between the new channel's
+ open and the proof got "Handshake required", which no retry treats as a
+ dropped connection, and the download died with that text in the transfers
+ panel. Only the opening messages pass now (`SESSION_OPENING`, held to
+ `dispatch.py` by `test_reconnect_race.py`), and a replaced channel's late
+ `close` no longer clobbers the new one. `harness/reconnect_race_harness.mjs`
+ runs the real `connect()`, `_reconnectLoop` and pipeline against a node that
+ refuses before the proof — the first harness here that does; the earlier
+ ones stub `connect`, which is exactly where this lived
+
+- **A push handler that re-fetches the world.** The interactive CLI answered
+ every `index_delta` by fetching and re-parsing the whole index, on the event
+ loop that was receiving the download: 67 full indexes in 80 s while a node
+ enriched a library (one delta a second). It applies the delta in place
+ (`Tree.apply_delta`), and only a delta that adds or removes files asks again,
+ once per burst
+
### More of the same, from four rounds of live testing
- **A protocol harness cannot test the SPA.** Any second implementation of the