docs!: Protocol 3.0 cutover — the 3.0 documentation set #73
@@ -970,14 +970,22 @@ push, and Play (M6–M8) follow the designed app.
|
|||||||
(`atlas`). Note the path: `/public/atlas`, **not** `/public/shard` — the atlas is static shard
|
(`atlas`). Note the path: `/public/atlas`, **not** `/public/shard` — the atlas is static shard
|
||||||
*content*, not live shard *state*, and unlike `/shard/*` it **is** `siteMode`-gated like
|
*content*, not live shard *state*, and unlike `/shard/*` it **is** `siteMode`-gated like
|
||||||
`/posts` and `/wiki`, so a site in maintenance mode withholds it independently of the sidecar.
|
`/posts` and `/wiki`, so a site in maintenance mode withholds it independently of the sidecar.
|
||||||
Two units/naming traps from `v3.md` §6.3: respawn delays are **seconds** throughout, and
|
Three traps. Two are units/naming, from `v3.md` §6.3: respawn delays are **seconds**
|
||||||
`points` is a *count* on the search route while `spawners` is the *list* on the detail route.
|
throughout, and `points` is a *count* on the search route while `spawners` is the *list* on
|
||||||
|
the detail route. The third is a **shape**: `places` is a list of
|
||||||
|
`{facet, label, spawners, maxAlive}` **objects**, not of place-name strings — it is the
|
||||||
|
aggregate the screen exists to show ("Shrines, Isamu-Jima, Yew"), it arrives only on the
|
||||||
|
detail route, and typing it `List<String>` makes that whole route fail to decode while the
|
||||||
|
request itself returns `200`.
|
||||||
- **Verification** — the five-rung walk (`anonymous`, `logged_in`, `player`, `staff`, `admin`)
|
- **Verification** — the five-rung walk (`anonymous`, `logged_in`, `player`, `staff`, `admin`)
|
||||||
against a local website on the cutover branch, per
|
against a local website on the cutover branch, per
|
||||||
[`../link/v3.md`](../link/v3.md) §11 and the shard-visibility smoke harness; plus one pass with
|
[`../link/v3.md`](../link/v3.md) §11 and the shard-visibility smoke harness; plus one pass with
|
||||||
**every feature disabled** in Admin → Shard Visibility, confirming the app *hides* each surface
|
**every feature disabled** in Admin → Shard Visibility, confirming the app *hides* each surface
|
||||||
instead of erroring on it. Unit tests cover the menu filter (role × feature set), the
|
instead of erroring on it. Unit tests cover the menu filter (role × feature set), the
|
||||||
`404`/`403`/`503` mapping, and DTO decode for each new shape.
|
`404`/`403`/`503` mapping, and DTO decode for each new shape. **Decode tests must feed real
|
||||||
|
captured JSON**, not DTOs built in Kotlin: the fakes under `data/api/fake/` construct objects
|
||||||
|
directly, so they can never catch a wire/type mismatch — which is how the `places` shape above
|
||||||
|
shipped past a green suite.
|
||||||
- **Excluded**, in the same class as M10's exclusions: the admin *configuration* panels — Shard
|
- **Excluded**, in the same class as M10's exclusions: the admin *configuration* panels — Shard
|
||||||
Visibility, Spawn Atlas and Cliloc import — alongside the hero/CMS block editor, Discord-bot
|
Visibility, Spawn Atlas and Cliloc import — alongside the hero/CMS block editor, Discord-bot
|
||||||
config, uo-link config and OAuth-provider setup.
|
config, uo-link config and OAuth-provider setup.
|
||||||
|
|||||||
27
link/v3.md
27
link/v3.md
@@ -350,8 +350,11 @@ Sidecar — `store.rs`: singleton `ruleset(id CHECK(id=1), rev, json, updated_t)
|
|||||||
`main.rs`: new arm in the board-projection match; `web.rs`: `GET /ruleset` served from the store, so
|
`main.rs`: new arm in the board-projection match; `web.rs`: `GET /ruleset` served from the store, so
|
||||||
it answers during a shard outage (`PROTOCOL_2.md` §12.2).
|
it answers during a shard outage (`PROTOCOL_2.md` §12.2).
|
||||||
|
|
||||||
Website — `uoLinkClient.getRuleset()`; `uoLinkSocket.backfill()` (object-shaped, so follow the
|
Website — `uoLinkClient.getRuleset()`; `uoLinkSocket.backfill()` (object-shaped, so it cannot use the
|
||||||
`getPresence()` block's explicit form, not the array-only `snapshot()` helper); `shardIngest.js` →
|
array-only `snapshot()` helper — but it **must still go through `shardIngest.ingest()`**, as
|
||||||
|
`ingestEach` does, rather than calling `shardState.setRuleset` directly: the two arrival orders have
|
||||||
|
to produce the same stored frame, and a direct call quietly made backfill a second writer that
|
||||||
|
skipped the normalization below); `shardIngest.js` →
|
||||||
`shardState.setRuleset`, **not** in `LOGGED_KINDS` (it re-arrives every reconnect and `server.hello`
|
`shardState.setRuleset`, **not** in `LOGGED_KINDS` (it re-arrives every reconnect and `server.hello`
|
||||||
already marks those); `KIND_FEATURE['world.ruleset'] = 'ruleset'`; `shard_ruleset` singleton table
|
already marks those); `KIND_FEATURE['world.ruleset'] = 'ruleset'`; `shard_ruleset` singleton table
|
||||||
(`rev`, `expansion`, `payload JSON`, `t`); `GET /public/shard/ruleset` behind
|
(`rev`, `expansion`, `payload JSON`, `t`); `GET /public/shard/ruleset` behind
|
||||||
@@ -360,6 +363,17 @@ already marks those); `KIND_FEATURE['world.ruleset'] = 'ruleset'`; `shard_rulese
|
|||||||
Client — NEW `routes/public/Rules.jsx` at `/site/rules`, alongside
|
Client — NEW `routes/public/Rules.jsx` at `/site/rules`, alongside
|
||||||
`/site/champs|guilds|governors|houses`; live via `useShardFeed({ filter: new Set(['world.ruleset']) })`.
|
`/site/champs|guilds|governors|houses`; live via `useShardFeed({ filter: new Set(['world.ruleset']) })`.
|
||||||
|
|
||||||
|
**The `shard` field falls back to the instance's own name.** ServUO ships `Server.cfg` with
|
||||||
|
`Name=My Shard`, so an operator who never edited it publishes that verbatim — which is the shard
|
||||||
|
saying *unnamed*, not naming anything, and the rules page then reads "My Shard" under a header
|
||||||
|
carrying the real one. `shardIngest` substitutes `settings.getInstanceName()` (the admin-editable
|
||||||
|
site title, else `BRAND_NAME` — the same resolution `getPublic().brand.name` uses, so one install
|
||||||
|
never shows two names) when `shard` is absent, blank, or exactly the stock default, matched
|
||||||
|
case-insensitively and trim-tolerantly but only as a **whole** value: a shard genuinely called
|
||||||
|
*"My Shard Reborn"* has named itself and keeps it. Applied at **ingest**, not on read, because the
|
||||||
|
ruleset is also broadcast live — the same object goes to the SSE fan-out, so a read-time
|
||||||
|
substitution would be undone by the next reconnect's frame.
|
||||||
|
|
||||||
### 5.4 Risk
|
### 5.4 Risk
|
||||||
|
|
||||||
Perf is nil (~3 KB per connect). The only real risk is publishing a secret, mitigated by the explicit
|
Perf is nil (~3 KB per connect). The only real risk is publishing a secret, mitigated by the explicit
|
||||||
@@ -638,6 +652,15 @@ Client — NEW `routes/public/Leaderboards.jsx` at `/site/leaderboards`; a "Loya
|
|||||||
added to `components/CharacterSheet.jsx`, one edit serving both `PlayerCharacter.jsx` and
|
added to `components/CharacterSheet.jsx`, one edit serving both `PlayerCharacter.jsx` and
|
||||||
`AdminCharacter.jsx`.
|
`AdminCharacter.jsx`.
|
||||||
|
|
||||||
|
**An unscored board still renders a row.** Most systems on a young shard have `top: []`, and a page
|
||||||
|
of blank cards reads as broken rather than as new — so a board with no entries shows a single
|
||||||
|
placeholder bearing the **instance's own name** with an em dash where a score goes, above the
|
||||||
|
existing "nobody has earned points here yet" line. It is deliberately **not** shaped like an entry —
|
||||||
|
no rank, no medal, no bar, muted — because a placeholder that looked like a real standing would be a
|
||||||
|
fabricated one; the first real entry replaces it outright. Purely presentational: the API keeps
|
||||||
|
sending an empty `top`, so no consumer ever receives an invented row. Web and app render it the same
|
||||||
|
way (`Leaderboards.jsx`, `LeaderboardsScreen.kt`).
|
||||||
|
|
||||||
### 7.5 What the run against a real shard changed
|
### 7.5 What the run against a real shard changed
|
||||||
|
|
||||||
The plan above was written from reading `PointsSystem.cs`. Booting the actual shard (ServUO 57.4, a
|
The plan above was written from reading `PointsSystem.cs`. Booting the actual shard (ServUO 57.4, a
|
||||||
|
|||||||
Reference in New Issue
Block a user