fix(shard): answer with the instance name when the shard is unnamed
ServUO ships Server.cfg with `Name=My Shard`. An operator who never edited it publishes that verbatim, so the rules page read "My Shard" under a header carrying the real name. That value is the shard saying *unnamed* rather than naming anything, so the site now answers with its own. `settings.getInstanceName()` resolves `site_title || BRAND_NAME` — the same resolution `getPublic().brand.name` already uses, so an install that set only the site title can never show two different names on two pages. Bare `brand.name` would have been wrong for exactly that case. Substituted at INGEST rather than on read: world.ruleset is also broadcast live, and the same object is handed to the SSE fan-out, so a read-time fix would be undone by the next reconnect's frame. Matched case- and padding-insensitively but only as a whole value, so a shard genuinely called "My Shard Reborn" keeps its name. Fixes a second ruleset writer found on the way: uoLinkSocket.backfill() called shardState.setRuleset directly instead of going through the dispatcher as ingestEach does, so the boot/reconnect snapshot silently skipped this normalization. The two arrival orders have to produce the same stored frame. Also renders a placeholder row on an unscored leaderboard — the instance name with an em dash where a score goes, deliberately not shaped like an entry (no medal, no bar) because a placeholder that looked like a real standing would be a fabricated one. Presentation only; the API still sends an empty `top`. Verified live against the shard + sidecar: rules page and leaderboards on web and Android both correct. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U7CBg11prhLimL9iHSX1bP
This commit is contained in:
@@ -142,9 +142,15 @@ async function backfill() {
|
||||
// snapshot() (which asserts an array under `key`). The shard also re-emits
|
||||
// world.ruleset on its own connect — this covers the other order, where the
|
||||
// sidecar was already up and holding the ruleset when WE reconnected.
|
||||
//
|
||||
// Routed through the dispatcher rather than straight to shardState, exactly as
|
||||
// ingestEach does for the array-shaped boards: the two orders must produce the
|
||||
// same stored frame, and calling setRuleset directly here made this a second
|
||||
// write path that silently skipped the shard-name normalization the live frame
|
||||
// gets. One writer, one set of rules.
|
||||
const ruleset = await uoLinkClient.getRuleset()
|
||||
if (ruleset.ok && ruleset.data && ruleset.data.ruleset) {
|
||||
await shardState.setRuleset(ruleset.data.ruleset)
|
||||
await shardIngest.ingest(ruleset.data.ruleset, { fromBackfill: true })
|
||||
log.info('snapshotted shard ruleset from /ruleset', { rev: ruleset.data.ruleset.rev })
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user