diff --git a/overlay/Config/Bridge.cfg b/overlay/Config/Bridge.cfg
index 7a5ef92..ef09957 100644
--- a/overlay/Config/Bridge.cfg
+++ b/overlay/Config/Bridge.cfg
@@ -14,7 +14,7 @@ Port=7788
QueueCap=10000
# Sweep intervals, seconds. Measured on a 150-character shard: a vitals sweep costs
-# 0.0015 ms/char, so 1000 online players is ~1.5 ms per sweep. See docs/PLAN.md §1.
+# 0.0015 ms/char, so 1000 online players is ~1.5 ms per sweep. See https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PLAN.md §1.
StatSweepSeconds=30
DecaySweepSeconds=60
EconomySweepSeconds=300
@@ -29,7 +29,7 @@ ChampSweepSeconds=10
# support queue; the full open queue is also available on demand via pages.snapshot.
PageSweepSeconds=5
-# Guild roster poll (docs/PROTOCOL_2.md Part B). Guilds expose only EventSink.JoinGuild, so
+# Guild roster poll (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md Part B). Guilds expose only EventSink.JoinGuild, so
# create/disband/leave/leader/alliance changes are found by diffing BaseGuild.List on this
# interval (emit guild.update / guild.remove). Guild membership moves slowly; 60s is ample.
GuildSweepSeconds=60
@@ -85,7 +85,7 @@ AdminReasonMaxLength=400
# Clamp on a timed ban's duration, seconds. A ban with no/zero duration is indefinite.
AdminBanMaxDurationSec=31536000
-# Account provisioning (docs/PROTOCOL_2.md Part A). Which side may mint game accounts:
+# Account provisioning (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md Part A). Which side may mint game accounts:
# website — the website is the authority; pair with Accounts.AutoCreateAccounts=false
# (else an in-game login of any new name still mints an account).
# game — the game server is the authority; website account.create is refused.
diff --git a/overlay/Scripts/Custom/Bridge/BridgeAccountLink.cs b/overlay/Scripts/Custom/Bridge/BridgeAccountLink.cs
index 5e0b1ef..24f98ed 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeAccountLink.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeAccountLink.cs
@@ -18,7 +18,7 @@ namespace Server.Custom.Bridge
/// and replies link.ok. The tag persists to accounts.xml across restarts.
///
/// The code table and the account write both live on the Core thread. The websiteUserId in
- /// link.confirm is trusted only because the socket is loopback-only (docs/PLAN.md §2); if the
+ /// link.confirm is trusted only because the socket is loopback-only (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PLAN.md §2); if the
/// sidecar ever moves off-host, gate it behind a shared secret.
///
public static class BridgeAccountLink
diff --git a/overlay/Scripts/Custom/Bridge/BridgeAccounts.cs b/overlay/Scripts/Custom/Bridge/BridgeAccounts.cs
index e076eab..ef414e2 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeAccounts.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeAccounts.cs
@@ -8,7 +8,7 @@ using Server.Misc;
namespace Server.Custom.Bridge
{
///
- /// The account provisioning plane (docs/PROTOCOL_2.md Part A): website-driven account
+ /// The account provisioning plane (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md Part A): website-driven account
/// creation and unlinking. Companion to BridgeAccountLink (the in-game [link flow), which
/// is unchanged.
///
@@ -18,7 +18,7 @@ namespace Server.Custom.Bridge
/// Both handlers run on the Core thread (BridgeBoot marshals inbound lines through
/// Timer.DelayCall first), so they touch accounts freely.
///
- /// Trust model matches the admin plane (docs/ADMIN_CONTROLS.md §5): authorization lives on
+ /// Trust model matches the admin plane (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/ADMIN_CONTROLS.md §5): authorization lives on
/// the website; the shard trusts the loopback + token socket and a required "actor" field.
/// The one shard-side floor on unlink is BridgeAdmin.Protected — a protected staff account is
/// never unlinkable from the web. The whole create plane is opt-in via SignupMode /
diff --git a/overlay/Scripts/Custom/Bridge/BridgeAdmin.cs b/overlay/Scripts/Custom/Bridge/BridgeAdmin.cs
index b82d893..28ea0ef 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeAdmin.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeAdmin.cs
@@ -13,7 +13,7 @@ namespace Server.Custom.Bridge
/// Every handler runs on the Core thread (BridgeBoot marshals inbound lines through
/// Timer.DelayCall first), so they may touch accounts, mobiles, and the network freely.
///
- /// Trust model (docs/ADMIN_CONTROLS.md §5): authorization is enforced on the *website* —
+ /// Trust model (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/ADMIN_CONTROLS.md §5): authorization is enforced on the *website* —
/// these commands are gated there behind admin/moderator roles. The shard trusts the
/// loopback socket exactly as town-crier does, and applies inbound commands with an implicit
/// CoOwner authority. Its one hard floor is : a command refuses any
@@ -248,7 +248,7 @@ namespace Server.Custom.Bridge
/// Opens an admin.audit frame (origin=web) with the common fields. Broadcast to every
/// connected dashboard so the website's moderation log stays complete regardless of which
/// client issued the action. The in-game counterpart (origin=in-game) is emitted from
- /// BridgeEvents; see docs/ADMIN_CONTROLS.md §5.5.
+ /// BridgeEvents; see https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/ADMIN_CONTROLS.md §5.5.
///
private static System.Text.StringBuilder AuditBegin(string action, string actor, string target)
{
diff --git a/overlay/Scripts/Custom/Bridge/BridgeConfig.cs b/overlay/Scripts/Custom/Bridge/BridgeConfig.cs
index 4ddd13e..21907ce 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeConfig.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeConfig.cs
@@ -5,7 +5,7 @@ namespace Server.Custom.Bridge
///
/// Which side may mint game accounts. Governs the bridge's inbound account.create verb;
/// the in-game first-login auto-create is a separate core setting (Accounts.AutoCreateAccounts)
- /// the operator pairs with this (docs/PROTOCOL_2.md §2).
+ /// the operator pairs with this (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md §2).
///
public enum SignupMode
{
@@ -43,7 +43,7 @@ namespace Server.Custom.Bridge
public static int TownCrierMaxActive { get; private set; }
public static int TownCrierMaxDurationSec { get; private set; }
- // Town Cryer news gump (docs/PROTOCOL_2.md §16).
+ // Town Cryer news gump (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md §16).
public static int NewsMaxTitleLength { get; private set; }
public static int NewsMaxBodyLength { get; private set; }
public static int NewsMaxExternal { get; private set; }
@@ -55,7 +55,7 @@ namespace Server.Custom.Bridge
public static int AdminReasonMaxLength { get; private set; }
public static int AdminBanMaxDurationSec { get; private set; }
- // ---- account provisioning (docs/PROTOCOL_2.md Part A) ----
+ // ---- account provisioning (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md Part A) ----
public static SignupMode Signup { get; private set; }
public static bool AccountCreateEnabled { get; private set; }
public static bool RequireIpForCreate { get; private set; }
@@ -89,7 +89,7 @@ namespace Server.Custom.Bridge
if (ChampSweepSeconds < 1)
ChampSweepSeconds = 1;
- // Social/political sweeps (docs/PROTOCOL_2.md Part B). Both change slowly, so the
+ // Social/political sweeps (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md Part B). Both change slowly, so the
// defaults are unhurried; the pass is a handful of field reads over a small set.
GuildSweepSeconds = Config.Get("Bridge.GuildSweepSeconds", 60);
if (GuildSweepSeconds < 1)
diff --git a/overlay/Scripts/Custom/Bridge/BridgeGovernance.cs b/overlay/Scripts/Custom/Bridge/BridgeGovernance.cs
index c2b33b6..c2858f0 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeGovernance.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeGovernance.cs
@@ -6,7 +6,7 @@ using Server.Engines.CityLoyalty;
namespace Server.Custom.Bridge
{
///
- /// The town-governor stream (docs/PROTOCOL_2.md §10.2). In modern ServUO the "mayor of a
+ /// The town-governor stream (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md §10.2). In modern ServUO the "mayor of a
/// town" is the Governor in the City Loyalty System (King Blackthorn's governance): each of
/// the governed cities has a Governor, a GovernorElect, and an Election. None of these raises
/// an EventSink, so — like and — the set
diff --git a/overlay/Scripts/Custom/Bridge/BridgeHousing.cs b/overlay/Scripts/Custom/Bridge/BridgeHousing.cs
index bca9d1c..31fe51a 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeHousing.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeHousing.cs
@@ -7,7 +7,7 @@ using Server.Multis;
namespace Server.Custom.Bridge
{
///
- /// The housing registry (docs/PROTOCOL_2.md §11 #9). BridgeSweeps already emits house.decay
+ /// The housing registry (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md §11 #9). BridgeSweeps already emits house.decay
/// *transitions*; this is the complementary *board*: one row per house with owner, location,
/// region, co-owners, value, and current decay level, so the website can render an owner→houses
/// map. Like the other Part B boards it is a diff sweep over BaseHouse.AllHouses — emit
diff --git a/overlay/Scripts/Custom/Bridge/BridgeJson.cs b/overlay/Scripts/Custom/Bridge/BridgeJson.cs
index 1b19135..9d73789 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeJson.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeJson.cs
@@ -8,7 +8,7 @@ namespace Server.Custom.Bridge
{
///
/// Outbound JSON is written by hand into a StringBuilder. It runs on the Core thread for
- /// every emitted event, and the measured budget in docs/PLAN.md assumes this cost, not a
+ /// every emitted event, and the measured budget in https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PLAN.md assumes this cost, not a
/// reflection serializer's.
///
/// Inbound JSON is parsed with JavaScriptSerializer. Commands arrive at human rates, so
diff --git a/overlay/Scripts/Custom/Bridge/BridgeNews.cs b/overlay/Scripts/Custom/Bridge/BridgeNews.cs
index c766406..294d35d 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeNews.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeNews.cs
@@ -8,7 +8,7 @@ namespace Server.Custom.Bridge
{
///
/// Website news articles pushed into the modern Town Cryer News gump
- /// (docs/PROTOCOL_2.md §16). Distinct from BridgeTownCrier, which drives the scrolling-crier
+ /// (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md §16). Distinct from BridgeTownCrier, which drives the scrolling-crier
/// announcement lines (GlobalTownCrierEntryList). Here the full article — title, body (HTML),
/// image, and a "more info" URL — becomes a TownCryerNewsEntry in TownCryerSystem.NewsEntries,
/// which the stock news gumps already render (they branch on TextDefinition.Number, so string
diff --git a/overlay/Scripts/Custom/Bridge/BridgePresence.cs b/overlay/Scripts/Custom/Bridge/BridgePresence.cs
index d0a50f9..e164c2b 100644
--- a/overlay/Scripts/Custom/Bridge/BridgePresence.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgePresence.cs
@@ -6,7 +6,7 @@ using Server.Mobiles;
namespace Server.Custom.Bridge
{
///
- /// The presence stream (docs/PROTOCOL_2.md §11 #1/#2): who is online and where. Two parts:
+ /// The presence stream (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md §11 #1/#2): who is online and where. Two parts:
///
/// presence.online - a periodic population snapshot (total, per-facet, per-region), emitted
/// on a sweep but only when it changes, so the site has a live "N online"
diff --git a/overlay/Scripts/Custom/Bridge/BridgeProfile.cs b/overlay/Scripts/Custom/Bridge/BridgeProfile.cs
index 4e08ede..dd3a30b 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeProfile.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeProfile.cs
@@ -15,7 +15,7 @@ namespace Server.Custom.Bridge
///
/// A profile is the single most expensive read in the bridge (~0.07 ms + ~2.4 KB at the
/// seeded scale, more for a fully-kitted character), so it is built on demand only, never in
- /// a sweep. See docs/PLAN.md §1.
+ /// a sweep. See https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PLAN.md §1.
///
public static class BridgeProfile
{
@@ -83,7 +83,7 @@ namespace Server.Custom.Bridge
}
sb.Append(']');
- // worn equipment only — not the backpack/bank (see docs/PLAN.md §IV.4)
+ // worn equipment only — not the backpack/bank (see https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PLAN.md §IV.4)
sb.Append(",\"equipment\":[");
first = true;
foreach (var item in m.Items)
@@ -104,7 +104,7 @@ namespace Server.Custom.Bridge
}
///
- /// The titles a character holds (docs/PROTOCOL_2.md §10.3). `selected` is the index into
+ /// The titles a character holds (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md §10.3). `selected` is the index into
/// `reward` currently displayed (-1 if none). `fameKarma` and `skill` are the computed
/// display titles (may be absent). `reward` is the raw reward-title list — an entry may be
/// a cliloc number (as a string) or a literal string; resolve clilocs website-side.
diff --git a/overlay/Scripts/Custom/Bridge/BridgeSocial.cs b/overlay/Scripts/Custom/Bridge/BridgeSocial.cs
index 2bd1b1b..48b756d 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeSocial.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeSocial.cs
@@ -7,7 +7,7 @@ using Server.Guilds;
namespace Server.Custom.Bridge
{
///
- /// The guild stream (docs/PROTOCOL_2.md §10.1). Guilds have almost no useful EventSink:
+ /// The guild stream (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PROTOCOL_2.md §10.1). Guilds have almost no useful EventSink:
/// EventSink.CreateGuild is only the load-time deserialization factory (Server/World.cs), and
/// leave/disband/leader/alliance changes raise nothing. Only EventSink.JoinGuild is real. So,
/// exactly like , the roster is polled: enumerate BaseGuild.List each
diff --git a/overlay/Scripts/Custom/Bridge/BridgeSweeps.cs b/overlay/Scripts/Custom/Bridge/BridgeSweeps.cs
index 9630ee2..0de3fb0 100644
--- a/overlay/Scripts/Custom/Bridge/BridgeSweeps.cs
+++ b/overlay/Scripts/Custom/Bridge/BridgeSweeps.cs
@@ -11,7 +11,7 @@ namespace Server.Custom.Bridge
///
/// The three polled streams, for state that has no EventSink: player vitals, house decay,
/// and money supply. All three run on the Core thread via repeating Timers, and the
- /// measured cost (docs/PLAN.md §1) is why they can: at the seeded scale a full pass of all
+ /// measured cost (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PLAN.md §1) is why they can: at the seeded scale a full pass of all
/// three is well under a millisecond.
///
/// Timers do not fire during a world save (Timer.cs:322), so a sweep that would have landed
diff --git a/patches/BridgeModerationAudit.cs b/patches/BridgeModerationAudit.cs
index 2b5c686..9565816 100644
--- a/patches/BridgeModerationAudit.cs
+++ b/patches/BridgeModerationAudit.cs
@@ -9,7 +9,7 @@ namespace Server.Custom.Bridge
///
/// Forwards IN-GAME uses of the write-plane verbs to the website as admin.audit
/// (origin=in-game), so the site's moderation log is complete regardless of whether an action
- /// came from the website or a staff member in the game client. See docs/ADMIN_CONTROLS.md §5.5.
+ /// came from the website or a staff member in the game client. See https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/ADMIN_CONTROLS.md §5.5.
///
/// Two sources, mirroring how the shard records each:
/// - ban / kick: resolved with their target inside the stock generic command, which logs a
diff --git a/patches/README.md b/patches/README.md
index d59b8b0..070d6bc 100644
--- a/patches/README.md
+++ b/patches/README.md
@@ -11,7 +11,7 @@ git apply patches/.patch
## Phase 7 — player-vendor sale (a coupled unit)
-Player-vendor purchases raise **no** EventSink. `ValidVendorPurchase` / `ValidVendorSell` cover NPC vendors only. The commit point is `PlayerVendorBuyGump.OnResponse`, the only place where buyer, vendor **owner**, price, and commission are all in scope — exactly what cheat detection needs. See `docs/PLAN.md` §6.
+Player-vendor purchases raise **no** EventSink. `ValidVendorPurchase` / `ValidVendorSell` cover NPC vendors only. The commit point is `PlayerVendorBuyGump.OnResponse`, the only place where buyer, vendor **owner**, price, and commission are all in scope — exactly what cheat detection needs. See [PLAN.md](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PLAN.md) §6.
This is the one non-drop-in piece. Apply all three together:
@@ -56,4 +56,4 @@ Phase 0 modifies an existing file but ships as a whole-file overlay (`overlay/Sc
## Note on shard repairs
-The deletions and edits described in `docs/SHARD_PREREQS.md` are one-time repairs to a specific broken install, not part of the bridge. They are not shipped here.
+The deletions and edits described in [SHARD_PREREQS.md](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/SHARD_PREREQS.md) are one-time repairs to a specific broken install, not part of the bridge. They are not shipped here.
diff --git a/tools/scaffolding/README.md b/tools/scaffolding/README.md
index f548e30..e5d0688 100644
--- a/tools/scaffolding/README.md
+++ b/tools/scaffolding/README.md
@@ -2,7 +2,7 @@
**Not part of the bridge. Never deployed.** `deploy.ps1` only copies `overlay/`, so nothing here reaches a server unless you put it there by hand.
-These two scripts produced the measured budget in `docs/PLAN.md` §1. They are kept because those numbers should be reproducible, and because re-running the probe is the only honest way to check whether a change to the plugin's read path got more expensive.
+These two scripts produced the measured budget in [PLAN.md](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PLAN.md) §1. They are kept because those numbers should be reproducible, and because re-running the probe is the only honest way to check whether a change to the plugin's read path got more expensive.
| File | Server path when testing | What |
|------|--------------------------|------|