Skip to content

v0.9.2 — 24-agent hardening (mini-nodes-are-routers)

Choose a tag to compare

@knobcore knobcore released this 22 Jun 07:25

Hardening pass landing the "mini-nodes are routers" architecture cleanly. Web/browser surfaces removed; librats frozen at v0.2.0; mini-node + full-node + player all tightened against the failure modes seen in the prior week.

Cellular wedge fix (three layers)

  • Android REQUEST_IGNORE_BATTERY_OPTIMIZATIONS one-shot prompt so Doze stops throttling the Dart isolate
  • Discovery refresh dropped 60s → 20s + paired bidirectional mini.ping to fill the gap between librats's 15s TCP keepalive and the application-layer heartbeat (carrier NAT was silently closing idle mappings in that window)
  • Watchdog evicts stale _miniNodePeerIds and _relayVia when validatedPeerIds.isEmpty so the next refresh repopulates from scratch instead of routing to ghost peer_ids

Mini-node (router) hardening

  • Routes table now has a 10-min TTL + 30s reaper thread; was: routes lingered forever after the publishing full node disappeared
  • 'F'-tag binary relay token-bucket rate-limit (50 MB bucket, 10 MB/s refill per peer)
  • Dead-route eviction on relay.forward send-failure + {status:dead_route} reply so the player re-picks a different full node immediately
  • RatsLink watchdog tick 3s → 1s; route republish on every validated-peer count increase (not just first-up); eager 127.0.0.1 bootstrap in addition to the colocated-VPS loopback fallback (librats blocks dialing own public IP)

Full node (server/tracker) hardening

  • SwarmIndex::evict_peer wired to disconnect callback so online entries no longer linger 20 min after a silent socket death
  • rats_announce_for_hash(sha1(content_hash)) fires on every fingerprint.submit — DHT-based content discovery is now live on the seeder side
  • RelayCreditTracker pre-caps count at 1M per tx (chain ceiling) with carry-over of the overflow into the next sweep

Player hardening

  • bestMiniNodePeerId picks lowest load_score (was: arbitrary validatedPeerIds.first)
  • Direct-when-reachable carve-out: desktop player whose own routes.get echo shows reachability=='direct' tries direct librats dial before falling back to relay
  • findContentSeeders(contentHash) adapter delegates to findHashHolders(sha1(...)) for DHT content lookup
  • stream.open disk-streamed (was: file.readAsBytes loaded whole song into RAM); 4-chunk pacing; cancel API wired to peer disconnect
  • Disconnect now triggers cancelStreamsForPeer so the player stops blasting bytes at a dead receiver

Removed

  • musicchain_web/ entirely (browser/web player path abandoned)
  • ws_mini_gateway, ws_audio_bridge, ws_tcp_relay, ws_bridge, audio_fetch_handler (browser-facing C++)
  • All browser-protocol docs under musicchain/docs/
  • Full-node --ws-port flag and the port 9090 WebSocket bridge

Frozen

  • deps/librats/ reset byte-for-byte to v0.2.0 (commit 246557c); future limitations are wrapped at the call site (rats_link.cpp, rats_client.dart), never inside librats

Docs + memory

  • New canonical reference: musicchain/ARCHITECTURE.md
  • Memory bank updated: feedback-no-web-version, feedback-dont-modify-librats, feedback-load-aware-routing, feedback-no-stale-peer-routing, project-architecture-doc

APK

Bundled below: musicchain-player-v0.9.2-arm64-v8a.apk (87.5 MB). Install:

adb install -r musicchain-player-v0.9.2-arm64-v8a.apk

First launch will prompt for battery-optimization exemption (Doze).

Known limitations (also tracked in ARCHITECTURE.md §8)

  • RELAY_REWARD still per-stream, not per-byte
  • No application-layer ACKs on binary relay (backpressure is time-paced, not credit-based)
  • Single VPS in current dev/test deployment; multi-VPS mesh ready in code but not exercised here