* phpbox: survive any host's limits and keep streams alive across handovers
Found on a local emulation of a free host (Apache + PHP-FPM, 60 s CPU per request,
the host's disabled functions, a gateway that gives up on the request):
- disabled set_time_limit/ignore_user_abort/getmypid/getenv/ini_set ended the node
at once under PHP 8 (a disabled function is undefined): guarded everywhere; ping
lists what the host took away
- time budget per generation on both clocks (CPU on Linux, wall on Windows/macOS,
RLIMIT_CPU), handover early when CPU runs short, and learning: a generation that
died early leaves its age in host.json and the next ones plan below it; on a host
not yet proven, handovers start at 40 s and grow as generations end well
- cups: the carrier slept 18 ms per message inside the loop (a 64 KB frame ~0.4 s),
so under a download new connections timed out and acks waited; now a paced
outbox in the mux: control frames first, streams in turn, whole packets per
message, at most ~72 KB/s (the server drops a member that sends faster)
- two generations in one room: each now ignores the other's messages (and its own
echoes, before decoding them), and messages carry whole packets, so a packet cut
across messages is never mixed with another member's bytes; the Go cupsonline
receiver keeps one reassembly buffer per member
- a successor takes streams only after its link stayed up 8 s (a Mail.ru document
drops new connections right after they join, and streams handed over then died)
- a repeated OPEN is answered again instead of redialled; the client asks again
after 4 s without an answer
- the page restarts a node that ended without Stop while it is open
- --mode=stream without --inbound is SOCKS5 on every OS again (macOS took utun)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* phpbox: send to cups only as fast as the server confirms; release rebuilds an existing tag
- the cups server shows every member's message back to it; our own coming back is
its confirmation. At most 6 unconfirmed messages: past that the server is behind,
and the client's OPENs and its pings queued behind our echoes (close 3012
'no pong' under a download). The link's close code and reason go to the log.
- release.yml: a moved tag replaces the release's assets and notes, as the apps do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* phpbox: count the cups server's echoes reliably; learn a host limit only from two deaths
- echoes were matched with a regex on the raw line that never matched the server's
JSON, so the window waited out its 3 s timeout each time (~6 KB/s under load):
a substring test on the member uuid instead; a live room confirms 10 of 10
- one sudden end (a host restart) no longer teaches a limit that shortens every
run for a week: two ends at about the same age do
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* phpbox: hand over early and consistently; never reach for a longer run than the host allows
The emulated hosts exposed the real cause of the node dying: the 'hold idle to prove a
longer run' recorded a lifetime (107s) longer than a host's hidden wall-clock kill (90s),
so later generations set their handover past that limit and were killed before they could
start a successor - the chain broke with no generation left to carry the lesson.
- a generation now hands over at ~2/3 of the known limit, never later than 45s, even on a
host that looks generous: a free host's real limit is unknown until a generation dies by
it, and that death must happen after a successor exists. Deaths only lower it.
- removed the idle hold and the lifetime-growth; a learned wall/CPU limit still lowers the
handover, and a wall limit is believed only after two deaths at a similar age
- while a successor shares the room, the predecessor caps its reading (OVERLAP_RATE): the
document server copies our download to the successor too, and at full speed the client's
OPENs to the successor waited behind it
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* CHANGELOG: the node-survival and stream-proxy fixes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* CHANGELOG: fold the node-survival fixes into 0.3.0 (rebuilt in place)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: p1neappleXpress <a@a.a>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* phpbox: a successor writes nothing, so a closed request cannot end it; the self-request checks its answer
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* streamproxy test: wait for the relay to count the last bytes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: p1neappleXpress <a@a.a>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>