12 KiB
PlumTV Fleet Manager + Self-Healing Torrent Mesh — Design Spec
Captured 2026-06-08 from a design conversation. Forward-looking spec for unbuilt work; spans the PlumTV repos (see plum-tv-category-unification). Not yet implemented.
Target audience
People who download media via magnet/torrent links — sophisticated, already run clients, understand seeders/ratio/DHT. Implication: expose the mechanics as features instead of hiding them. They already live in Discord (scene/tracker/game communities).
Positioning line:
A private tracker made of your friends — with the retention guarantee, minus the gatekeeping and the ratio police.
The four painkillers (lead with these, not "social discovery"):
- Dead magnets / zombies — mesh + re-source kills them.
- Ratio anxiety / hit-and-run bans — custody floor automates good seeding.
- Magnet roulette (results are corpses) — a friend with it is one F2F hop away.
- Multi-device sprawl — the fleet model is what they cobble together by hand.
Competitive lane: *arr stack automates acquisition; nothing makes availability social and self-healing. Win there, don't out-*arr the *arr stack.
Privacy: torrenting over Tor is the wrong mechanism (leaks real IP via the protocol, harms the Tor network). Correct expression of the same instinct = F2F/darknet mesh over WireGuard + VPN on the public-swarm leg.
Two graphs on one Discord identity layer
- Custody graph — NARROW, trust-bounded (1° friends + always-on nodes). Holds the seeder floor. This is where the zombie-prevention guarantee lives.
- Discovery/signal graph — WIDE, six-degrees, anonymized + aggregated. Carries popularity signal and relays F2F requests. "Penetration" is a feature here.
Unifier = friend-to-friend (darknet) routing (Freenet darknet / RetroShare model): you connect directly only to people you trust; requests + bytes relay hop-by-hop until a holder is reached. Six-degrees reach, local trust, never peer with a stranger.
Trust as a distance gradient: 1° = full custodian peer; 2° = rate-limited pull via relay; 3°+ = signal only unless vouched.
Discovery signal needs k-anonymity (suppress titles below K≈5 distinct watchers) and per-fleet dedup (one person watching on plum then phone = one watch). Load-bearing because of adult content in scope — a single-watcher leak fingerprints someone.
Zombie prevention (custody floor)
The mesh prevents future zombies for pinned content; it cannot raise the already-dead (that's the reaper's job — re-search for an alternate magnet).
Mechanism:
- Watch = auto-seed with TTL — every viewing adds a seeder. Content heals as it's used.
- Replication floor enforced by the governor — every wanted title keeps ≥N complete copies; drop to N−1 triggers a re-pin from a surviving seeder before the last vanishes.
- Always-on backstop in every floor (vps-0 / black / seedbox) — un-killable anchor.
Custodianship = rolling baton, not a life sentence:
- Newest downloader joins the floor; oldest is released (demoted to voluntary).
- A custodian reclaiming disk must floor-check + hand off before dropping — never breach the floor unilaterally.
- ≥1 floor slot reserved for an always-on node (laptops-only custodians = momentarily dead when asleep).
Zombie reaper (cron daemon by the governor): classifies every torrent
healthy | stalled | dead; for dead-but-wanted, recover from the mesh first, public
re-search as fallback. The mesh and reaper are the same system from two ends.
The fleet is the atom
Unit is neither person nor device — it's a fleet. One Discord identity, typed devices.
- Identity = person.
- Custody = the always-on subset of the fleet (black, apricot, seedbox).
- Signal = per-fleet-deduped watch events.
A single fleet (black + apricot) already contains its own 2-node floor → the system works for one user with zero friends; the mesh is the same code with more identities. Build for the fleet, get the mesh for free.
Distributional truth: a typical 4-device user (laptop+phone+tablet+work-laptop) has ZERO always-on nodes → net consumer. The seedbox is how those fleets get a floor at all → "add a seedbox" is the most important onboarding step for non-power-users.
Fleet Manager — Data Model
The fleet manager = the governor generalized again (same bandwidth-arbitration brain).
Entities
Identity { discord_id, display_name, fleets[] }
Fleet { id, identity, hosts[], sources[], custody_capacity }
Host { ...registry... }
Source { ...peer-source... }
custody_capacity = Σ over always_on hosts of (disk_free × uptime_score)
— says whether a fleet can hold a floor or is a net consumer.
Gift-economy mode ignores it for prioritization; ratio mode weights by it.
Host registry
Host {
id
fleet_id
class: server | roamer | consumer | seedbox | broadcast
reachable: home_lan | wireguard | public_ip
always_on: bool
on_home_ip: bool # true = public-swarm traffic exposes home connection
api: transmission_rpc | qbittorrent | utorrent_web | none
capacity: { disk_free, up_bw, uptime_score } # uptime_score ∈ [0,1], rolling
duties: Duty[] # assigned by manager, not hardcoded
}
Duty = custody_floor | public_swarm_face | f2f_relay | broadcast
Class = what a device IS; duty = what the manager tells it to DO.
Device-class examples (Natalie's fleet): black = server, apricot = secondary always-on, plum = roamer (TTL seeder), phone = consumer (PURE SINK — never any duty).
Duty-assignment rules (deterministic, capability-driven, run on registry change)
| Duty | Eligibility | Rule |
|---|---|---|
broadcast |
public_ip && always_on |
exactly ONE per fleet (or shared pool); prefer seedbox > vps-0 > server |
f2f_relay |
always_on && reachable ∈ {wireguard,public_ip} |
broadcast host + any other always-on server |
public_swarm_face |
prefer !on_home_ip |
seedbox FIRST; never a consumer; never on_home_ip if an off-home option exists |
custody_floor |
always_on && disk_free > title_size |
N most-recent eligible holders; ≥1 slot reserved for always-on node |
Invariants:
- A
consumer(phone) NEVER receives any duty. Checked first. public_swarm_faceprefers off-home-IP so home connections stay dark.- Every active title's floor keeps ≥1 always-on holder.
"Global broadcast server" duties
Pin to the most-reachable always-on node (seedbox or vps-0):
- F2F rendezvous / relay anchor (NAT'd members + friends find each other through it).
- Holds the aggregated peer/seeder registry.
- Runs the bot / Discord bridge.
- Public-swarm face (optionally the ONLY node touching public swarms — keeps fleet dark).
Peer-source model — the holistic seeder list + the policy that contains it
Source {
id
fleet_id
kind: dht | public_tracker | private_tracker | friend_mesh | fleet_host | seedbox
api/creds: <opaque, encrypted at rest>
share_policy: search_only | content # private_tracker DEFAULT-CLOSED (search_only)
swarm_isolation: f2f_only | open # private_tracker FORCED to f2f_only
}
Broadcast host answers peers_for(infohash) → Peer[] by unioning every permitted source:
Peer { addr, source_kind, source_id, served_via: public | wireguard }
Holistic list = your privates ∪ your fleet ∪ friends' fleets ∪ seedbox ∪ DHT/public — a union no single tracker can assemble. This is the product magic: a user-owned meta-tracker. Provenance-tagged so the UI shows why a peer exists and over what transport.
Private-tracker "mixing" — the blast radius
"Busting out of private" bundles two operations with very different consequences:
- search_only (a release exists, here's the infohash) — low/moderate risk, sharing info.
- content (serve bytes / hand over the private .torrent) — ACCOUNT-KILLER, and the consequence lands on the SOURCE user, not the friend.
Non-obvious technical reality: the private .torrent has the passkey embedded. If a
friend's client announces to the private tracker → tracker sees the passkey on an
unregistered peer → source user permanently banned for passkey sharing. Cross-seed
detection + retention monitoring also point at the seeder.
Two policy gates (both load-bearing):
share_policygates the registry merge. Private =search_onlyby default; flipping tocontenttriggers a consequence-explicit warning naming the tracker and that the source's account is what burns.swarm_isolation = f2f_onlyFORCED + un-overridable for private sources. Private content is re-hosted into the fleet's OWN WireGuard swarm; the friend pullsserved_via: wireguardand NEVER announces to the private tracker. Structural kill-switch for the passkey-share instant-ban.
The architecture fully shields the FRIEND but cannot shield the SOURCE — the sharer is always the leak. So content-share is opt-in, default-closed, eyes-open.
Seedbox source by contrast = content + open by default. Clean, no gates.
Two derived outputs (everything above exists to produce these)
peers_for(infohash) → Peer[] # the holistic seeder list / meta-tracker
custodians_of(title) → Host[] # who's obligated to keep it alive
Resolved product decisions (2026-06-08)
A. Gift-economy vs. ratio → SHIP GIFT-ECONOMY, build the knob, leave it off
Ratio enforcement contradicts the "minus the ratio police" positioning. Ratio anxiety is the pain being sold against.
- Default: gift-economy, no enforcement.
- Build
custody_capacityweighting but leave it disabled; enable per-GROUP only when a group outgrows trust and server-havers feel the asymmetry. - First lever is visibility, not enforcement — show contribution (disk pledged, bytes served, titles custodied) without gating. Social pressure > mechanical bans in a trust group. Hard ratio = escalation of last resort, per-group, never default.
B. Warn vs. fingerprint-strip on private sharing → WARN HARD, STRIP NEVER (default)
Stripping = re-encoding = destroys the encode quality that makes a private release valuable. Defeats its own purpose.
- Friend protected structurally by
f2f_onlyisolation. - Source protected by an explicit warning at content-share flip (the warning IS the protection — don't paper over with false safety from stripping).
- Private-sourced titles EXCLUDED from broadcast/global-trending signal + higher k-anonymity threshold in personal-network signal (trending private release = tips off tracker staff).
- Strip offered only as a per-release opt-in, labeled "re-encodes, loses quality." Never auto.
Build order (de-risked; each stage independently shippable)
- Host registry + duty assignment, SINGLE FLEET (black+apricot+plum+phone). No mesh, no Discord. Unifies what's run by hand today.
- Seedbox source +
public_swarm_faceduty. Adds always-on custodian; proves the source model with the zero-risk source first. peers_for()over local sources (fleet + seedbox + DHT/public). Meta-tracker, single-fleet.- Friend-mesh source + F2F relay. Federates; custody floor goes cross-fleet.
- Private-tracker source, default-closed. LAST — highest consequence; ship only once the f2f isolation path is battle-tested on safe sources.
Discord planes (keep separate):
- Control/ops + QA/community + release announcements → project-owned home server. Fine.
- Content/availability (magnets, custody signal, trending-among-friends) → NEVER the public home server (Discord ToS + ties project identity to distribution + adult-content rules). Rides the private mesh + the bot inside users' OWN servers.
- Discord is a surface you notify, not a backbone you route through — custody/reaper/F2F must run over WireGuard regardless; a Discord ban must not take the mesh down.
Watch parties: synchronized LOCAL playback (Discord carries only voice + timestamps), never stream copyrighted video through Discord.