docs(installer): record Phase 4 — doctor, update and uninstall as built

The installer crate now implements the whole command surface INSTALL.md
published before the binary existed, so this records what Phase 4 turned
out to be and corrects two places where the plan and the guide had drifted
apart.

PLAN.md
  - Status header: Phases 1–4 are on `edge`; the edge → main cutover now
    cuts a binary that does everything INSTALL.md describes, with Phase 5
    being packaging polish rather than capability.
  - A Phase 4 "as built" section: why `update` is the install pipeline in
    a different mode rather than a second implementation, why it neither
    reprints the token nor stays quiet about a protocol change, the tier's
    scope under `update` (re-resolve what was applied, without re-asking;
    name what is new), how `doctor` asks the binary the way the service
    does, the exit-code rule and why a stopped shard is a ⚠ while a
    running one that has not dialed in is a ✗.
  - §5's uninstall table: the cached patch set and patches/originals/ move
    from "removed" to "kept". The report that command prints tells the
    operator to diff against those originals — deleting them made the
    advice impossible to follow within one command's output. `--purge`
    removes them.

INSTALL.md
  - §2: exit codes stated (`doctor` and `uninstall` use 1 for a completed
    run that found something wrong), `--patches` now applies to `update`,
    `--yes` means yes on `uninstall`, `--purge` covers the patch cache.
  - §7 doctor: the real row set, what ✓/⚠/✗ mean, that it writes nothing
    and is safe to run with the shard up.
  - §7 update: it updates the tree install.json names, needs the shard
    stopped, does not reprint the token, calls out a protocol change, and
    what it does and does not do with the patch tier.
  - §7 uninstall: what survives, that edited files are flagged in the
    listing, the confirmation's default, and where the report file lands.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-05 03:00:45 -05:00
parent 706b450828
commit ecef87f120
2 changed files with 150 additions and 27 deletions

View File

@@ -213,12 +213,17 @@ reports "unchanged" and writes nothing.
| `--verify` | `install`, `update` | Dry run. Report every change that would be made; write nothing. |
| `--servuo <path>` | `install`, `doctor`, `update` | Name the ServUO root instead of detecting or prompting. |
| `--bundle <tag>` | `install`, `update` | Pin an exact published bundle instead of the current one. |
| `--patches` / `--no-patches` | `install` | Decide the patch tier non-interactively. `--patches` never loosens the region check: patches whose target lines are not stock are reported for you to apply by hand, not forced. |
| `--patches` / `--no-patches` | `install`, `update` | Decide the patch tier non-interactively. `--patches` never loosens the region check: patches whose target lines are not stock are reported for you to apply by hand, not forced. On `update` it is what takes up a feature the shard does not already have. |
| `--patches-unsupported-servuo` | `install` | Required *in addition to* `--patches` to run the patch tier on a ServUO that is not 57.4. Unsupported and untested — see [§4](#4-the-patch-tier-optional). Ignored on 57.4. |
| `--host <name>` | `install` | The hostname to print in the website URLs. |
| `--site-url <url>` | `install` | Your site's base URL, for the Admin → Shard link. |
| `--yes` | all | Assume the default answer to every prompt. Combine with the flags above for an unattended run. |
| `--purge` | `uninstall` | Also delete `sidecar.toml` and `uo-link.db`, which are otherwise kept. |
| `--yes` | all | Assume the default answer to every prompt. Combine with the flags above for an unattended run. **On `uninstall` it means yes** — that prompt defaults to no, and typing `uninstall --yes` is not an accident. |
| `--purge` | `uninstall` | Also delete `sidecar.toml`, `uo-link.db` and the cached patch set, all of which are otherwise kept. |
Exit codes are `0` success, `1` the run failed, `2` the arguments were unusable. Two commands also
use `1` for a run that *completed* and found something wrong, so they can be read from a script:
`doctor` when any check failed, and `uninstall` when a step could not be carried out (everything
else still was).
---
@@ -504,21 +509,41 @@ The command that makes this supportable. Run it before asking anyone for help
first thing a maintainer will want.
```
✓ Install record /etc/runicgateway/install.json (bundle 2026.08.04, installer 1.0.0, …)
✓ ServUO found /opt/ServUO (57.4)
✓ Overlay in sync 24 files, all hashes match install.json
⚠ Patch tier 1 of 3 applied (region-match) — vendor.sale unavailable
✓ uo-link installed 1.1.0
✓ Service running, enabled
✓ Sidecar reachable 127.0.0.1:8080 /health ok
⚠ Patch tier 1 applied — moderation-audit (region-match)
✓ uo-link installed uo-link-sidecar 1.1.0 (protocol 3)
config /etc/runicgateway/sidecar.toml database /var/lib/runicgateway/uo-link.db
✓ Service runicgateway-link.service active, enabled as runicgateway
✓ Sidecar reachable 127.0.0.1:8080 /health ok, up 6h, database ok
✓ Protocol sidecar 3 = overlay manifest 3
✗ Shard connected no shard has dialed in since boot
✗ Shard connected no — the shard is running (pid 8123) but has not dialed in
✓ Bundle 2026.08.04 — up to date
```
Three of those rows come from asking the installed sidecar (`--version`, `--print-config`) rather
than from reading `install.json`, so `doctor` reports what the binary would actually do — including
which config and database file the *service* resolves — rather than what the installer believes it
was told. The overlay row compares live file hashes against both `install.json` and the release
manifest, which is how it tells "you edited a deployed file" from "the overlay moved on".
Rows come from asking the installed sidecar (`--version`, `--print-config`) rather than from reading
`install.json`, so `doctor` reports what the binary would actually do — including which config and
database file the *service* resolves — rather than what the installer believes it was told. The
overlay row compares live file hashes against `install.json`, which is how it tells "you edited a
deployed file" from "the file is gone"; the bundle row is what tells you the overlay upstream has
moved on. Each patched file is re-checked against the cached copy of its patch, so a core upgrade or
a restored backup that quietly removed the tier's edits is caught here — nothing else would notice.
It writes nothing at all, and it is safe to run while the shard is up; that is in fact the only
state in which the last row can be `✓`.
**Reading the marks:**
| | |
|---|---|
| `✓` | as it should be |
| `⚠` | worth knowing, not broken — a stopped shard, a service you never registered, an unpatched tier, or no route to Gitea to check for a newer bundle |
| `✗` | broken. `doctor` exits `1` if any row is `✗`, so it can be run from a monitoring script; a `⚠` never causes that |
The distinction on the last row is worth spelling out: **shard not running** is a `⚠` (start it),
while **shard running and not dialed in** is a `✗` — that is the silent failure this whole guide
warns about, where ServUO reports a clean boot over a script build that failed.
### `runicgateway update`
@@ -532,6 +557,21 @@ together — never to two independently-latest artifacts that may disagree.
Your `sidecar.toml`, your `Bridge.cfg` edits and your database are not touched. `Bridge.cfg` is
overwritten only if you have not changed it; a modified copy is reported, not clobbered.
It updates the ServUO tree `install.json` names — not a tree it detects — and it needs the shard
stopped, exactly as `install` does. There is nothing to update on a host that was never installed;
it says so rather than performing a first install under a verb that promises to preserve.
**Your auth token is not reprinted.** It has not changed and your website already has it. The one
thing an update can change that the site must be told about is the **protocol version**, and it says
so plainly when that happens — a stale number in Admin → Shard is answered with `409` and looks
exactly like your shard going offline.
**The patch tier under `update`:** features you already have are re-checked against the new release
(normally nothing to do), without asking you again — you consented when they were installed, and
that includes a shard where the tier ran unsupported. Features you never took are **named, not
applied**; run `update --patches` (or `install --patches`) to take one up. A shard that declined the
tier stays unpatched through every update.
### `runicgateway uninstall`
Removes what it exclusively owns, and **prints** everything else. The installer cannot know what you
@@ -540,12 +580,19 @@ your work.
| | |
|---|---|
| **Removed** | The sidecar binary, its service entry, `install.json`, the cached patch set |
| **Kept** | `sidecar.toml` and `uo-link.db` — config and history survive (`--purge` drops them) |
| **Printed, not done** | Every overlay file deployed into your ServUO tree, by path, for you to delete |
| **Removed** | The sidecar binary, its service entry, `install.json` |
| **Kept** | `sidecar.toml`, `uo-link.db`, and the cached patch set with its pre-patch originals (`--purge` drops all of them) |
| **Printed, not done** | Every overlay file deployed into your ServUO tree, by path, for you to delete — with any file you have edited since deployment flagged, so you do not delete your own work by mistake |
| **Printed, not done** | The exact hunks each applied patch added to `EventSink.cs`, `PlayerVendorGumps.cs` and `Logging.cs`, for you to revert — with how each landed, since one placed into a file you had already modified is worth a closer look. The pre-patch copy kept under `patches/originals/` is there to diff against. |
The report is also written to a file, so it survives the scrollback.
It lists all of that **before** asking, and the prompt defaults to **no**. `--yes` proceeds, which is
what an unattended uninstall needs; nothing else about the command is destructive to your shard,
which is neither stopped nor started.
The report is also written to a file — `runicgateway-uninstall-<timestamp>.txt` in the directory you
ran the command from — so it survives the scrollback. That is why the cached patches and the
originals stay behind by default: they are the only offline record of what the tier changed once the
release tarball is gone, and the report tells you to diff against them.
---