Design

Prosperous is a target-management tool and the library underneath it. It registers a target, finds out what the target can do, puts payloads on it, reads its log, moves files, controls its processes and watches its output. The binary is pros; the window is pros-gui.

The library is the whole implementation and both programs are shims over it. Two kinds of consumer need that: the sibling projects, which call it from a diagnostic loop, and a person driving a target directly.

The target and its services

Prosperous speaks to services the entry point starts on the target. It adds no protocol of its own for them. The compiled-in list is pros_link::service::SERVICES:

Service Port Protocol Required
elfldr 9021 send an ELF, it runs yes
ftpsrv 2121 anonymous FTP yes
klogsrv 3232 /dev/klog as an endless stream no
shsrv 2323 a shell over raw TCP, not telnet no
pldmgr 8084 the payload manager and its dashboard no

The payload manager starts the rest from an autoload list on the target, and it launches everything through elfldr. When elfldr is gone nothing can be reloaded, including elfldr, and the dashboard still answers because it is a separate listener. A check that finds the loader missing therefore says to rerun the entry point, not to load a payload (Remedy::RerunTheEntryPoint).

Three facts about the transport shape the code:

Crates

crates/pros-link       the target services: transport only, over std::net
crates/pros-core       registry, checks, the manifest, workflows
crates/pros-moonlight  the Moonlight bridge in front of Porthole
pros-cli               the `pros` shim
pros-gui               the window shim

The line between them is drawn at what needs a dependency.

The repositories are checked out together under the OOPS root and joined by relative path dependencies. A standalone clone of a consumer does not build; that is the cost of not running a release process for pros-link.

Registration

A registration holds only what a power cycle cannot change: a name, an address, port overrides by service name, and the startup chain the target is meant to run. The registry is one line per target, <name> <address> [service=port ...] [chain=<name>], in the collection's shared data directory resolved through oops_paths, so sibling projects reach the same targets. There is no ambient current target: every operation names one.

What a target can do is never stored. Loaded services do not survive a power cycle, so a cached capability is a claim that expires without notice. It is probed on every use.

Checks

A check reports what each service unlocks, not up or down. A missing required service blocks every workflow; a missing optional one dims the view, because less is visible when something fails. The verdict is Ready, Dimmed or Blocked with a remedy.

The doctor turns findings into a repair plan: a payload the target lacks is fetched from the manifest, verified, sent and listed in the chain. A plan is confirmed by a person before it runs, and where more than one payload would answer, the choice is offered rather than made.

Timing is part of the answer. A port that refuses at once is a machine saying no; one that takes the full timeout is usually the network. A probe carries its duration and the reporting layer decides what to remark on.

The chain is a separate question from the check: what the target loads when it comes back, read from the payload manager's autoload list. A service that answers now and is absent from the chain is gone after the next power cycle.

Payloads

Prosperous ships no payload binaries. It ships a manifest of where to get them, editable outside the source tree so a moved mirror is a text edit rather than a release.

Capabilities

What Prosperous knows about a target falls into three layers, and only the middle one is configuration.

  1. Protocols are code. FTP is FTP whoever serves it; a socket that takes an ELF and runs it is a loader. Configuration never names a protocol this program has no code for.
  2. Providers are data. Which payload provides a capability, on which port, at which paths and in which file format. This is the layer that changes when a payload is replaced by another.
  3. Facts about the machine are code: /user/home, /user/app, /user/appmeta, the SFO layout, the save container shape. A configurable machine fact invites a confidently wrong answer with no second opinion to catch it.

The test for a layer: if a different entry point would change it, it is a provider; if only a different machine would, it is a machine fact.

A capability names what Prosperous needs, such as moving files, and lists the providers known to supply it. A capability is satisfied when any provider answers, and the report names which one, because "files, via zftpd" and "files" are different facts. Its speaks field names a protocol and is validated against what is compiled in when the file is read. A provider's dependencies are stated against capabilities, not payload names, so a root failure such as a missing loader is reported once and what follows from it is reported as following.

Two rules keep this honest:

Port overrides on a registration are the provider layer in its simplest form. Every connection goes through the registration, so an override reaches transfers as well as the probe. Manifest entries may declare unlocks and required, so a declared payload takes part in the verdict the same way a compiled-in service does.

Video

Watching and diffing are separate problems with no shared code. Watching goes through Porthole, a payload that encodes the target's output in hardware and serves it on a socket; pros-core::watch reads it, counts it and pipes it to a player, and pros-moonlight offers the same stream to any Moonlight client. Diffing goes through a resident frame grabber that returns one lossless frame on request, read by pros-link::frames (D008). Both are specified in VIDEO.md.

Testing without a target

The target is a physical machine on a network that is usually switched off. pros-link::fake is a loopback stand-in for the services, shipped rather than hidden in a test module so every consumer uses the same one. It fakes the awkward parts, because that is where the bugs are:

pros fake-target does the same for Porthole: it serves an Annex B file on 9805 and prints the pad records it receives on 9806, so the Moonlight bridge runs end to end on one machine.

A fake cannot say whether the target agrees. That takes a registered target and a manual run, and results say which of the two produced them.