feat(bridge): emit world.ruleset, the shard's published ruleset #3

Merged
whitlocktech merged 1 commits from feat/bridge-ruleset into edge 2026-07-28 20:37:07 +00:00
Member

Protocol 3.0 order 2 — docs/link/v3.md §5. Plugin half of a four-repo change.

What

A new BridgeRuleset.cs emitting one world.ruleset frame describing how this shard is actually configured: expansion, which optional systems are on, skill/stat caps, account and house limits, champion scroll rules, the save/restart schedule. The website renders it at /site/rules, so the rules page cannot drift from the server.

Modelled on BridgeBoot.EmitHello, not on the diff sweeps. The ruleset changes only when an operator edits a .cfg, so there is nothing to poll. It subscribes Connected_Core — a sidecar that comes up second still learns the ruleset — and [bridge reload re-emits, for an operator who just edited a file and wants it live without a shard restart.

The security-relevant part

The frame is built from an explicit allowlist of Config.Get calls. Config.Entries is never enumerated: that would sweep in every key on the server, secrets included. Server.cfg, Staff.cfg, Email.cfg, DataPath.cfg, Bridge.cfg, Compiler.cfg, Reports.cfg and Client.cfg are named as excluded in a code comment as well as in the spec.

The one connection detail published is Bridge.PublicConnectAddress — blank by default, set deliberately by an operator for this purpose. The shard's real listen address is never read.

Two details worth a reviewer's eye

  • rev is FNV-1a, not String.GetHashCode(). GetHashCode is seeded per process on modern .NET, so it would change on every shard restart and defeat the whole point of a diff.
  • Where a system's on/off state is derived, the frame reads the system's own static rather than inventing a .cfg key. Shadowguard.cfg has no Enabled (it's the TOL expansion gate); Factions.cfg has none either, because Services/Factions/Core/Faction.cs sets Settings.Enabled = !ViceVsVirtueSystem.Enabled — the two are mutually exclusive by construction.

Config (overlay/Config/Bridge.cfg)

Key Default
RulesetEnabled true master switch
PublicConnectAddress (blank) the only connection detail ever published
RulesetIncludeSchedule true off for an operator who'd rather not advertise a restart window

Verification

Compiled the entire ServUO Scripts tree (6,205 files, net48, Expansion EJ) with this overlay substituted for the deployed Bridge copy — clean, zero errors. Contrary to the repo's "no standalone build" caveat this is achievable with the SDK's Roslyn csc.dll at /langversion:7.3 against the net48 reference assemblies (excluding Scripts/obj and Scripts/bin); the method is recorded in v3.md §5 and is worth running on every plugin PR.

deploy.ps1 -Verify shows the expected single ADD Scripts\Custom\Bridge\BridgeRuleset.cs.

The emitted frame was validated end to end against the Rust sidecar and the website — see the sibling PRs.

Sibling PRs

  • link → GET /ruleset + the store projection
  • website → ingest, the public route, and /site/rules
  • docs → INTEGRATION.md catalog, PROTOCOL_2.md §10.4 superseded note, v3.md progress

PROTOCOL_VERSION is not bumped here; that is a single operator-visible cutover at the end of v3 (§4).


  • AI-assisted: written with Claude Code (Claude Opus 5), reviewed before opening.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U7CBg11prhLimL9iHSX1bP

Protocol 3.0 order 2 — [`docs/link/v3.md` §5](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/edge/link/v3.md). Plugin half of a four-repo change. ## What A new `BridgeRuleset.cs` emitting one `world.ruleset` frame describing how this shard is actually configured: expansion, which optional systems are on, skill/stat caps, account and house limits, champion scroll rules, the save/restart schedule. The website renders it at `/site/rules`, so the rules page cannot drift from the server. **Modelled on `BridgeBoot.EmitHello`, not on the diff sweeps.** The ruleset changes only when an operator edits a `.cfg`, so there is nothing to poll. It subscribes `Connected_Core` — a sidecar that comes up second still learns the ruleset — and `[bridge reload` re-emits, for an operator who just edited a file and wants it live without a shard restart. ## The security-relevant part The frame is built from an **explicit allowlist** of `Config.Get` calls. `Config.Entries` is never enumerated: that would sweep in every key on the server, secrets included. `Server.cfg`, `Staff.cfg`, `Email.cfg`, `DataPath.cfg`, `Bridge.cfg`, `Compiler.cfg`, `Reports.cfg` and `Client.cfg` are named as excluded in a code comment as well as in the spec. The one connection detail published is `Bridge.PublicConnectAddress` — blank by default, set deliberately by an operator for this purpose. The shard's real listen address is never read. ## Two details worth a reviewer's eye - **`rev` is FNV-1a, not `String.GetHashCode()`.** `GetHashCode` is seeded per process on modern .NET, so it would change on every shard restart and defeat the whole point of a diff. - **Where a system's on/off state is *derived*, the frame reads the system's own static rather than inventing a `.cfg` key.** `Shadowguard.cfg` has no `Enabled` (it's the TOL expansion gate); `Factions.cfg` has none either, because `Services/Factions/Core/Faction.cs` sets `Settings.Enabled = !ViceVsVirtueSystem.Enabled` — the two are mutually exclusive by construction. ## Config (`overlay/Config/Bridge.cfg`) | Key | Default | | |---|---|---| | `RulesetEnabled` | `true` | master switch | | `PublicConnectAddress` | *(blank)* | the only connection detail ever published | | `RulesetIncludeSchedule` | `true` | off for an operator who'd rather not advertise a restart window | ## Verification Compiled the **entire ServUO Scripts tree** (6,205 files, net48, Expansion EJ) with this overlay substituted for the deployed Bridge copy — clean, zero errors. Contrary to the repo's "no standalone build" caveat this is achievable with the SDK's Roslyn `csc.dll` at `/langversion:7.3` against the net48 reference assemblies (excluding `Scripts/obj` and `Scripts/bin`); the method is recorded in `v3.md` §5 and is worth running on every plugin PR. `deploy.ps1 -Verify` shows the expected single `ADD Scripts\Custom\Bridge\BridgeRuleset.cs`. The emitted frame was validated end to end against the Rust sidecar and the website — see the sibling PRs. ## Sibling PRs - link → `GET /ruleset` + the store projection - website → ingest, the public route, and `/site/rules` - docs → `INTEGRATION.md` catalog, `PROTOCOL_2.md` §10.4 superseded note, `v3.md` progress `PROTOCOL_VERSION` is **not** bumped here; that is a single operator-visible cutover at the end of v3 (§4). --- - [x] AI-assisted: written with **Claude Code** (Claude Opus 5), reviewed before opening. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01U7CBg11prhLimL9iHSX1bP
wtclaude added 1 commit 2026-07-28 19:40:46 +00:00
Protocol 3.0 §5 (docs/link/v3.md). One frame describing how this shard is
actually configured — expansion, which optional systems are on, skill/stat
caps, account and house limits, champion scroll rules, the save/restart
schedule — so the website's rules page cannot drift from the server.

Modelled on BridgeBoot.EmitHello, not on the diff sweeps: the ruleset changes
only when an operator edits a .cfg, so there is nothing to poll. It subscribes
Connected_Core, so a sidecar that comes up second still learns the ruleset,
and `[bridge reload` re-emits for an operator who just edited a file.

The frame is built from an EXPLICIT ALLOWLIST of Config.Get calls. Config.Entries
is never enumerated — that would sweep in every key on the server, secrets
included — and Server.cfg, Staff.cfg, Email.cfg, DataPath.cfg, Bridge.cfg,
Compiler.cfg, Reports.cfg and Client.cfg are named as excluded both here and in
a code comment. The one connection detail published is Bridge.PublicConnectAddress,
blank by default, which an operator sets deliberately for this purpose.

`rev` is FNV-1a over the body so an unchanged reconnect is a site-side no-op.
String.GetHashCode() is deliberately not used: it is seeded per process, so it
would change on every restart and defeat the diff.

Verified by compiling the full ServUO Scripts tree (6,205 files, net48, EJ) with
this overlay substituted for the deployed Bridge copy — clean.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech approved these changes 2026-07-28 20:36:47 +00:00
whitlocktech merged commit a7a383e6d9 into edge 2026-07-28 20:37:07 +00:00
whitlocktech deleted branch feat/bridge-ruleset 2026-07-28 20:37:07 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/servuo-plugins#3
No description provided.