122 lines
7.8 KiB
Markdown
122 lines
7.8 KiB
Markdown
# Status & Roadmap
|
||
|
||
Where the project is and the de-risked path to the full vision. Architecture is in
|
||
[architecture.md](./architecture.md); the mesh design origin is
|
||
[`../.project/history/20260608_fleet-manager-mesh-design.md`](../.project/history/20260608_fleet-manager-mesh-design.md).
|
||
|
||
## Status at a glance
|
||
|
||
| Area | Status | Note |
|
||
|---|---|---|
|
||
| App — playback (VLC / mpv / QuickTime) | ✅ Shipped | `blacktv` retired → mpv; no NFS — local players play downloads, else route to black |
|
||
| App — library browser | ✅ Shipped | black index fast-path + local `MEDIA_ROOTS` walk + registry fallback (no NFS) |
|
||
| App — downloads (search + transmission) | ✅ Shipped | via `mcp` CLI; search needs FlareSolverr |
|
||
| App — metadata enrichment + artwork | ✅ Shipped | regex parse + TMDB/IMDb/keyless + ffmpeg frame-grab |
|
||
| App — all UI (Home/Player/Library/Search/Downloads/Metadata/Adult/Devices/Logs/Settings) | ✅ Shipped | wired, no TODO/FIXME/`fatalError` debt |
|
||
| App — device registry (Devices tab) | ✅ Shipped (registry only) | `DeviceConfig`: type→services presets mapping to fleet classes, per-device load badge; duty *engine* still unbuilt (see fleet below) |
|
||
| App — adult content tab | ✅ Shipped | `porn-rotation.py` ported to `PornCollectionService`; `ENABLE_ADULT` compile flag + runtime `pornFeature` setting, concealed by default |
|
||
| App — VPN subsystem | ✅ Shipped | OVPN profile/credential stores (Keychain), controller, settings UI |
|
||
| App — offline cache + Now Playing/media keys | ✅ Shipped | `OfflineCacheController`, `NowPlayingController`, bandwidth policy |
|
||
| iOS app (`TVAnarchyiOS`) | ✅ Shipped (companion) | VLCKit player, library, downloads, remote control via HTTP bridge (default `:8787`); the bridge *server* is not in this repo's `mcp/` tree |
|
||
| Distribution (release/update) | ✅ Shipped | `tools/release.sh` → Forgejo on forge.black; `tools/update.sh` installs/updates any node without a toolchain |
|
||
| `governor` (`portable-net-tv`) | ✅ Shipped (single-host) | watch tracking + prefetch buffer |
|
||
| `mcp` (`plum-control-mcp`) | ✅ Shipped | VLC / black-tv / transmission / display tools |
|
||
| `recommender` | ✅ Shipped | enrichment + local recs |
|
||
| MLX title refiner | ⚠️ Seam only | `TitleRefiner` protocol + `refiner` hook, never assigned |
|
||
| `governor` → fleet orchestrator | ❌ Designed | duty assignment / replication floor / zombie reaper not built |
|
||
| `fleet/` (registry, mesh, `peers_for`/`custodians_of`) | ❌ Designed | README + spec, zero code |
|
||
| Discord planes | ❌ Designed | control/QA/announce + availability bot |
|
||
| Multi-identity / cross-fleet | ❌ Designed | single-fleet foundation must land first |
|
||
|
||
**Verdict:** the media-client layer is complete and production-grade. The
|
||
fleet/mesh layer — the project's defining "private tracker made of your friends" —
|
||
is fully specified and entirely unbuilt.
|
||
|
||
### Repo-state note
|
||
|
||
The `PlumTV → TVAnarchy` rename and the helper subsystems (`governor/`, `mcp/`,
|
||
`recommender/`, `search/`, `fleet/`, `tools/`) were committed to `main` on
|
||
2026-06-09 as a series of atomic commits (`41afc1c`…`b44b5a2`). Stage 0
|
||
(hygiene) below is **done**.
|
||
|
||
## Remaining work — detail
|
||
|
||
### MLX title refiner (parallel, low-risk)
|
||
|
||
`Sources/TVAnarchyCore/Metadata/FilenameParser.swift` declares
|
||
`public protocol TitleRefiner` and `public static var refiner: (any TitleRefiner)?`,
|
||
consulted only when regex yields a <2-char title. No type conforms to it and
|
||
`refiner` is never assigned — the pipeline is regex-only. Impact is low (regex
|
||
handles the vast majority of `SxxEyy` releases); this is a deliberate seam, not
|
||
debt. Closing it = an MLX-backed refiner for the messy tail.
|
||
|
||
### governor → fleet orchestrator
|
||
|
||
The spec wants the governor's bandwidth-arbitration brain extended to: run
|
||
duty-assignment on registry change, enforce the N-copy replication floor (re-pin
|
||
before the last copy vanishes), and run a zombie reaper
|
||
(`healthy | stalled | dead`; recover from mesh first, public re-search fallback).
|
||
Today the governor only does single-host watch-follow + prefetch. The
|
||
bandwidth/watch foundations are reusable; the orchestration layer is missing. This
|
||
is the actuation layer for the `fleet/` registry — without it a registry is inert.
|
||
|
||
### fleet/ — the mesh subsystem
|
||
|
||
`fleet/` is README-only. Everything in
|
||
[data-model.md](./data-model.md#planned-fleetmesh-data-model) — registry, duties,
|
||
peer-source policy, `peers_for`/`custodians_of` — is design-only.
|
||
|
||
## Build order (de-risked; each stage independently shippable)
|
||
|
||
From the design spec. Each stage ships on its own; later stages depend on earlier.
|
||
|
||
0. ~~**Hygiene (prerequisite)**~~ — ✅ done 2026-06-09: the `PlumTV → TVAnarchy`
|
||
rename and the helper subsystems are committed on `main`.
|
||
1. **Host registry + duty assignment, single fleet** (black + apricot + plum +
|
||
phone). No mesh, no Discord. Unifies what's run by hand today.
|
||
*Partially started on the app side:* the Devices tab + `DeviceConfig`
|
||
(`devices.json`) already model device **types** (cellphone/laptop/storage/
|
||
seedbox/broadcast → fleet classes consumer/roamer/server/seedbox/broadcast)
|
||
with overridable per-device **services** presets. What remains is the
|
||
governor-side duty *assignment engine* over that registry.
|
||
*(Run the governor-generalization track alongside stages 1–3.)*
|
||
2. **Seedbox source + `public_swarm_face` duty.** Adds an always-on custodian;
|
||
proves the source model on the zero-risk source first. ("Add a seedbox" is the
|
||
single most important onboarding step for non-power-users — most multi-device
|
||
fleets have zero always-on nodes otherwise.)
|
||
3. **`peers_for()` over local sources** (fleet + seedbox + DHT/public). The
|
||
user-owned meta-tracker, still single-fleet.
|
||
4. **Friend-mesh source + F2F relay.** Federates; the custody floor goes
|
||
cross-fleet. Multi-identity lands here.
|
||
5. **Private-tracker source, default-closed.** LAST and highest-consequence:
|
||
`swarm_isolation` forced to `f2f_only`, un-overridable; `content` share is an
|
||
account-killer for the source user. Ship only once F2F isolation is
|
||
battle-tested on safe sources.
|
||
|
||
**Parallel, any time:** MLX `TitleRefiner` (independent, low-risk).
|
||
**After a working mesh:** the Discord planes — control/ops + QA/community +
|
||
release announcements (project home server) and content/availability (private mesh
|
||
+ a bot inside users' *own* servers, never the public home server). Discord is a
|
||
surface you notify, not a backbone you route through: custody/reaper/F2F run over
|
||
WireGuard regardless, and a Discord ban must not take the mesh down.
|
||
|
||
## Non-goals / explicitly deferred (not defects)
|
||
|
||
- **`BlackTVTarget` removed.** Intentional — auto-migrated at runtime to `MpvTarget`
|
||
with `CommandsConfig.blackTVDefaults(bin:)`. Black-TV control still works.
|
||
- **No ratio enforcement.** Resolved decision (2026-06-08): ship gift-economy,
|
||
build the `custody_capacity` knob, leave it off. First lever is visibility, not
|
||
enforcement; hard ratio is a per-group last resort. Ratio anxiety is the pain
|
||
being sold against — "minus the ratio police."
|
||
- **No fingerprint-stripping on private shares.** Resolved decision: **warn hard,
|
||
strip never** by default. Stripping re-encodes and destroys the quality that
|
||
makes a private release valuable; the friend is protected structurally by
|
||
`f2f_only`, the source by the explicit warning. Strip is a per-release opt-in
|
||
only, never auto.
|
||
- **App doesn't link `governor` or call the MCP server directly.** By design — it
|
||
shells out to the `mcp` CLI and `recommender` as subprocesses; `governor` runs
|
||
independently under launchd.
|
||
- **Black-TV watch state not on plum.** Intentional — black-local, read over SSH,
|
||
never written across NFS.
|
||
- **Watch parties** (if built) = synchronized *local* playback; Discord carries
|
||
only voice + timestamps, never streamed copyrighted video.
|