docs(installer): plan the Runic Gateway installer #80

Merged
whitlocktech merged 1 commits from docs/installer-plan into main 2026-08-01 10:46:15 +00:00
Member

What & why

Adds installer/PLAN.md — the design of record for a deployment tool that takes a stock ServUO install and configures it for Runic Gateway. Planning only; no installer code exists yet.

It supersedes an informal overview that described a ServUO integration not matching how servuo-plugins actually ships. The corrections are not wording nits — each changes what the installer has to do:

  • There is no RunicGateway.dll and no Plugins/ dir. The plugin ships as C# source compiled by ServUO at boot, so the step is a hash-compare sync of overlay/ (22 bridge files + Bridge.cfg + Scripts.csproj). The sting: a successful copy does not mean a working bridge, because ScriptCompiler.Compile() ignores dotnet build's exit code and reloads the stale Scripts.dll — a shard boots clean on broken code.
  • Stock ServUO files are modified, by the three diffs in patches/. Made an explicit opt-in, skippable tier: git apply against a hand-modified shard will fail, and the EventSink.cs patch needs a full core solution rebuild, not the dynamic script build everything else relies on.
  • Config paths collided with what the sidecar actually reads. Split ownership — sidecar.toml keeps the sidecar's own schema, install.json is the installer's. Service definitions pin UOLINK_CONFIG and UOLINK_DB_PATH, since the sidecar writes relative to CWD and would fail or land in VirtualStore under Program Files.
  • The token handoff was missing entirely — the largest "I installed it and nothing happened" failure mode.
  • deploy.ps1 cannot be the cross-platform deployer (PowerShell-only; most Linux ServUO hosts have no pwsh). It stays the developer-facing tool; the installer reimplements the sync natively.

Release orchestration (§7)

The installer needs CI that reacts when a component publishes a release. That landed in the second commit, folded into version tracking because the bundle is the compat matrix — which closes the "where does the compat matrix live" gap §7 originally left open.

  • Bundle manifest — CI publishes an exact, protocol-checked combination of component versions. The installer resolves against it at run time; --bundle <tag> pins one. A link release regenerates ~20 lines of JSON and leaves the installer binary untouched, so operators don't re-download the installer for a sidecar patch. Two compose-time gates: sidecar PROTOCOL_VERSION must equal the overlay manifest's declared version, and every asset's SHA256 must match.
  • Triggers — each component's release job POSTs to the installer's workflow-dispatch endpoint (link/.gitea/workflows/release.yml already declares workflow_dispatch: {} and already holds a write:repository token), plus a nightly cron so a missed dispatch self-heals. repository_dispatch avoided; support is uncertain on this Gitea version.
  • Stale overlay: dispatch, don't wait — components self-release on merge to their own main, so the release normally already exists. If main is ahead with releasable commits (docs:/chore: correctly cut nothing), fire that repo's workflow, compose from what exists now, warn loudly, and let the nightly fold in the result. Dispatching another repo's workflow is fine — it still runs that repo's own gates — but polling it is not, since Gitea's dispatch endpoint returns no run handle.

Decisions locked

Public audience; unsigned binaries anchored on SHA256SUMS with SmartScreen warnings documented rather than hidden; Rust; release-tarball plugin distribution; bundle-manifest composition; printed token handoff; a new RunicGateway/installer repo; warn-and-skip on any ServUO other than stock 57.4; and an uninstall that never edits the shard tree — it removes uo-link and its service entry, then prints the overlay files to delete and the patch hunks to revert for the operator to action themselves.

Shape

Phases 0–5. Phase 0 gates everything else and is prerequisite work outside the installer: servuo-plugins has no release workflow today, so tarball distribution cannot happen until it gets one (the release engine in link/.gitea/workflows/release.yml was written to be retargetable, and its header says so), plus the bundle CI itself, since Phase 1 resolves what to install from the bundle.

Two open questions remain in §8, neither blocking Phase 0: whether to hard-assume ServUO/uo-link co-location (the shard dials loopback 127.0.0.1:7788, so today they must share a host), and branch targeting for the Phase 0 workflow while the v3 edge → main cutover is mid-flight.

How it was tested

Docs-only change — no build or tests to run. Every claim about the repos was verified against the working tree rather than taken from the source overview: servuo-plugins/overlay/ file list, servuo-plugins/deploy.ps1, servuo-plugins/patches/README.md, link/sidecar/src/config.rs, link/sidecar/src/main.rs (PROTOCOL_VERSION), link/.gitea/workflows/release.yml, and link/SHARD_PREREQS.md.

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

This project requires disclosure of AI tool usage. Please pick one:

  • No AI tools were used to produce this contribution.
  • AI tools were used. Tool(s): Claude Code (Opus 5). I have reviewed and understand
    every change, and take responsibility for it. AI-authored commits are
    marked with a Co-Authored-By / Assisted-By trailer.

License

  • I agree that my contribution is licensed under this project's license
    (GNU GPL v3.0 or later), and I have the right to contribute it.
## What & why Adds `installer/PLAN.md` — the design of record for a deployment tool that takes a stock ServUO install and configures it for Runic Gateway. Planning only; no installer code exists yet. It supersedes an informal overview that described a ServUO integration not matching how `servuo-plugins` actually ships. The corrections are not wording nits — each changes what the installer has to do: - **There is no `RunicGateway.dll` and no `Plugins/` dir.** The plugin ships as C# *source* compiled by ServUO at boot, so the step is a hash-compare sync of `overlay/` (22 bridge files + `Bridge.cfg` + `Scripts.csproj`). The sting: a successful copy does not mean a working bridge, because `ScriptCompiler.Compile()` ignores `dotnet build`'s exit code and reloads the stale `Scripts.dll` — a shard boots clean on broken code. - **Stock ServUO files *are* modified**, by the three diffs in `patches/`. Made an explicit opt-in, skippable tier: `git apply` against a hand-modified shard will fail, and the `EventSink.cs` patch needs a full **core** solution rebuild, not the dynamic script build everything else relies on. - **Config paths collided with what the sidecar actually reads.** Split ownership — `sidecar.toml` keeps the sidecar's own schema, `install.json` is the installer's. Service definitions pin `UOLINK_CONFIG` and `UOLINK_DB_PATH`, since the sidecar writes relative to CWD and would fail or land in VirtualStore under `Program Files`. - **The token handoff was missing entirely** — the largest "I installed it and nothing happened" failure mode. - **`deploy.ps1` cannot be the cross-platform deployer** (PowerShell-only; most Linux ServUO hosts have no `pwsh`). It stays the developer-facing tool; the installer reimplements the sync natively. ### Release orchestration (§7) The installer needs CI that reacts when a component publishes a release. That landed in the second commit, folded into version tracking because **the bundle *is* the compat matrix** — which closes the "where does the compat matrix live" gap §7 originally left open. - **Bundle manifest** — CI publishes an exact, protocol-checked combination of component versions. The installer resolves against it at run time; `--bundle <tag>` pins one. A `link` release regenerates ~20 lines of JSON and leaves the installer binary untouched, so operators don't re-download the installer for a sidecar patch. Two compose-time gates: sidecar `PROTOCOL_VERSION` must equal the overlay manifest's declared version, and every asset's SHA256 must match. - **Triggers** — each component's release job `POST`s to the installer's workflow-dispatch endpoint (`link/.gitea/workflows/release.yml` already declares `workflow_dispatch: {}` and already holds a `write:repository` token), plus a nightly cron so a missed dispatch self-heals. `repository_dispatch` avoided; support is uncertain on this Gitea version. - **Stale overlay: dispatch, don't wait** — components self-release on merge to their own `main`, so the release normally already exists. If main is ahead with *releasable* commits (`docs:`/`chore:` correctly cut nothing), fire that repo's workflow, compose from what exists now, warn loudly, and let the nightly fold in the result. Dispatching another repo's workflow is fine — it still runs that repo's own gates — but polling it is not, since Gitea's dispatch endpoint returns no run handle. ### Decisions locked Public audience; **unsigned** binaries anchored on `SHA256SUMS` with SmartScreen warnings documented rather than hidden; Rust; release-tarball plugin distribution; bundle-manifest composition; printed token handoff; a new `RunicGateway/installer` repo; **warn-and-skip** on any ServUO other than stock 57.4; and an **uninstall that never edits the shard tree** — it removes uo-link and its service entry, then prints the overlay files to delete and the patch hunks to revert for the operator to action themselves. ### Shape Phases 0–5. **Phase 0 gates everything else** and is prerequisite work outside the installer: `servuo-plugins` has no release workflow today, so tarball distribution cannot happen until it gets one (the release *engine* in `link/.gitea/workflows/release.yml` was written to be retargetable, and its header says so), plus the bundle CI itself, since Phase 1 resolves what to install *from* the bundle. Two open questions remain in §8, neither blocking Phase 0: whether to hard-assume ServUO/uo-link co-location (the shard dials loopback `127.0.0.1:7788`, so today they must share a host), and branch targeting for the Phase 0 workflow while the v3 `edge → main` cutover is mid-flight. ## How it was tested Docs-only change — no build or tests to run. Every claim about the repos was verified against the working tree rather than taken from the source overview: `servuo-plugins/overlay/` file list, `servuo-plugins/deploy.ps1`, `servuo-plugins/patches/README.md`, `link/sidecar/src/config.rs`, `link/sidecar/src/main.rs` (`PROTOCOL_VERSION`), `link/.gitea/workflows/release.yml`, and `link/SHARD_PREREQS.md`. ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) This project **requires disclosure of AI tool usage**. Please pick one: - [ ] No AI tools were used to produce this contribution. - [x] AI tools were used. Tool(s): `Claude Code (Opus 5)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` / `Assisted-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it.
wtclaude added 1 commit 2026-08-01 10:45:33 +00:00
Design of record for a deployment tool that takes a stock ServUO install and
configures it for Runic Gateway. Supersedes the informal overview it grew from,
which described a ServUO integration that does not match how servuo-plugins
actually ships.

Corrections that change the design:

- There is no RunicGateway.dll and no Plugins/ dir. The plugin ships as C#
  source compiled by ServUO at boot, so the step is a hash-compare sync of
  overlay/ -- but a successful copy does not mean a working bridge, because
  ScriptCompiler.Compile() ignores dotnet build's exit code and reloads the
  stale Scripts.dll.
- Stock ServUO files ARE modified, by three diffs in patches/. Made an opt-in,
  skippable tier: git apply against a hand-modified shard will fail, and the
  EventSink.cs patch needs a full core solution rebuild.
- Config paths collided with what the sidecar actually reads. Split ownership:
  sidecar.toml stays the sidecar's schema, install.json is the installer's.
  Service definitions pin UOLINK_CONFIG and UOLINK_DB_PATH, since the sidecar
  writes relative to CWD and would land in VirtualStore under Program Files.
- The token handoff was missing entirely -- the largest "installed it and
  nothing happened" failure mode.
- deploy.ps1 cannot be the cross-platform deployer; it stays the developer tool.

Decisions: public audience, unsigned binaries anchored on SHA256SUMS, Rust,
release-tarball plugin distribution, printed token handoff, new installer repo,
warn-and-skip on non-57.4 ServUO, and an uninstall that never edits the shard
tree -- it prints the files to delete and the hunks to revert.

Phases 0-5, with Phase 0 (a release workflow for servuo-plugins, which has
none today) gating everything else. Two open questions remain in section 8.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech merged commit c583ddb77f into main 2026-08-01 10:46:15 +00:00
whitlocktech deleted branch docs/installer-plan 2026-08-01 10:46:16 +00:00
Sign in to join this conversation.
No description provided.