Commit Graph

3 Commits

Author SHA1 Message Date
7027a78a23 feat(rust): --game rust, named instances, and schema-2 bundles (phase 18)
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 2m7s
Module-rust phase 18, step 5 of docs/modules/rust/PLAN.md §34.2.7 (D146,
D148, D149, D153).

Bundles: ServUO is read at schema 2 from v2/servuo/ and lowered into the
schema-1 model. Schema 1 at the root is the fallback, so a pin from before
schema 2 still reproduces. Rust bundles are read from v2/rust/. v2 reads use
the contents API, because /raw/ is CDN-cached for six hours.

--game rust runs install, update, doctor and uninstall for Rust servers
(src/rustgame/):
- the framework is detected from its marker files, which were read off both
  rigs; both or neither is refused;
- --server-id names an instance: its own service (runicgateway-rust@<id>, or
  RunicGatewayRust-<id>), config, database and ports;
- the plugin config is written once, with ServerId and Port only. An existing
  one is never rewritten, and one naming another server refuses the run;
- each instance's sidecar.toml is written once with its ports and an absolute
  database path, and the sidecar generates the token into it;
- one binary per host. update moves every instance, and a replaced binary
  restarts all of them;
- doctor checks the plugin file hash, the plugin config's ServerId, the
  required uMod plugins (a warning), the service and /health, and passes when
  the plugin is connected;
- uninstall removes our plugin and keeps its config. --purge also removes the
  sidecar config and database. The last instance takes the binary, the
  template and the record, and the shared user only when no ServUO record
  remains.

service.rs takes the service name as a parameter internally. The ServUO
public API is unchanged.

Finding: Carbon 2.0.259's config.json has no folder keys, so carbon/plugins
and carbon/configs are what the installer uses. The plan expected a moved
directory to be readable there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-09-25 23:40:11 -05:00
2787eaadff feat(installer): read bundles from the branch they are published to
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 1m58s
`main` is protected, so the compose job cannot push a bundle there --
the pre-receive hook declines it, which is not something a nightly cron
can resolve. Bundles now publish to a branch of their own, at its root,
so BUNDLE_BASE follows them. Everything the original choice was for
survives the move: a reviewable diff, a git history of the compat
matrix, and a plain anonymous URL that needs no credentials on the
shard host.

The test's bundle is now a frozen fixture rather than an include of the
published file, which this checkout no longer carries. Frozen is the
honest shape anyway: a test that silently re-targeted whatever CI
published last would change meaning without a commit. It is still a
real CI-emitted document, copied verbatim.

Nothing is released from `edge`, so no shipped binary ever read the old
URL.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-05 17:20:18 -05:00
52d330167b feat(installer): implement Phase 3 — the patch tier
Some checks failed
PR Checks / rust-gates (pull_request) Failing after 46s
Two features need edits to stock ServUO sources, because the events they
depend on do not exist. This adds the rung ladder of PLAN.md §2.2.1, the
unsupported-version path of §2.2.2, and the record and cache Phase 4 will read.

Three decisions were not settled by the plan:

* The engine is fully native, with no `git`. §2.2.1 wrote rung 1 as "apply
  verbatim with git apply", but §1 chose the release tarball specifically so
  there would be no git on the shard host, and rung 2 needs a native applier
  regardless. Rung 1 keeps its distinct, stronger verdict — the whole file
  reproduced the diff's `index` pre-image, computed as a git blob SHA1 in
  process — while the write goes through the same code path as rung 2. On the
  real trees here that is not academic: the shipped .patch files are CRLF in a
  Windows checkout and two of their three targets are LF, so `git apply`
  refuses patches this applies correctly.

* Per-patch metadata is declared by the release, with a built-in fallback.
  Which patches form one all-or-nothing unit, which companion .cs follows
  which, whether a CORE rebuild is needed and what declining costs are not
  derivable from a diff. servuo-plugins now declares them; overlay v0.1.1 is in
  the current bundle and declares nothing, so a built-in copy stands in for it.
  A checked-in fixture of the release workflow's own jq output asserts the two
  descriptions are identical, so the repos cannot drift quietly.

* Pre-images are cached in the state directory. The tier edits files the
  operator owns, and `/etc/runicgateway/patches/originals/` is what turns "here
  are the hunks we added" into a revert anyone can verify — kept out of the
  ServUO tree, which uninstall has promised never to clean up.

Everything else follows §2.2.1: exact matching with only line-ending and
trailing-whitespace normalization, exactly one occurrence or it fails,
all-or-nothing per patch file and again per feature, and a byte-preserving
splice so nothing outside a hunk can be reformatted.

Verified against the ServUO 57.4 tree on this machine across four scratch
roots: a hand-patched tree (rung 0), a reverse-applied stock one (rung 1 on the
real EventSink.cs, its blob matching the patch's declared pre-image), a
mixed-rung feature, a tree with edits inside two patched regions (rung 3 —
nothing written, nothing held back applied, no companions copied), and a
non-57.4 tree both with and without the extra consent flag. Three consecutive
runs left install.json byte-identical and the cached pre-image still pre-patch.

Three reporting defects the live runs caught are fixed with tests: a dry run
and a held-back patch both claimed to be "applied", the core-rebuild warning
fired when nothing had been written and named a Scripts file as core, and a
declined tier announced the loss of features install.json showed as applied.
Refused patches are now cached too, since the refusal message names that path.

Refs: docs/installer/PLAN.md §2.2, §5 Phase 3

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-04 19:54:36 -05:00