docs(link): record world.ruleset and mark Protocol 3.0 progress
Protocol 3.0 order 2 (v3.md §5) is built across all four repos; this is its
documentation half, plus the running progress record the plan was missing.
v3.md
- A progress table at the top and a State column on §9's sequencing table, so
"what has landed" is answerable without reading four git logs. Part A (order
1) and world.ruleset (order 2) are marked done; the spawn atlas is next.
- §5 gains the implementation notes worth keeping, chiefly: where a system's
on/off state is DERIVED rather than configured, read the system's own static
instead of inventing a .cfg key (Shadowguard has no Enabled key — it's the
TOL expansion gate; Factions is `!ViceVsVirtueSystem.Enabled` by
construction in stock ServUO). Also that the plugin CAN be compile-verified
despite the "no standalone build" caveat, and how.
INTEGRATION.md
- The world.ruleset catalog entry and GET /ruleset, with the two things
consumers get wrong: caps are in TENTHS (1000 = 100.0), and `connect` exists
only if the operator set Bridge.PublicConnectAddress — the shard's real
listen address is never published.
- §2 now says plainly that v3 has NOT been bumped yet and what that means:
sidecars on `edge` report 2 while already carrying some v3 kinds, so do not
infer feature availability from the version during this window.
PROTOCOL_2.md §10.4
- The deferred "which PvP system does this shard run?" is answered (VvV on,
Factions off — and mutually exclusive by construction), and world.systems is
marked superseded by world.ruleset, which carries the systems block it asked
for. No orphan kind is left behind.
BACKEND_DESIGN.md — the shard_ruleset table (why it is stored whole rather than
normalized, and why no row means null rather than {}) and the public route.
PROJECT_TREE.md is deliberately untouched: sync-project-tree regenerates it on
push to main, so it updates itself at the v3 cutover.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -99,7 +99,7 @@ server/
|
||||
pages.router.js (2) /public/pages — the draft-preview
|
||||
route precedes /:slug and is
|
||||
deliberately not site-mode gated
|
||||
shard.router.js (13) /public/shard/* incl. the anonymous
|
||||
shard.router.js (14) /public/shard/* incl. the anonymous
|
||||
SSE stream; never site-mode gated
|
||||
site.router.js (4) /settings /status /version /contact —
|
||||
the group-root singletons; declares no
|
||||
@@ -358,6 +358,23 @@ analogue to a password — and there is no hash-lookup constraint (verification
|
||||
unused rows and `bcrypt.compare`s each, like password verification). `used_at` is the single-use
|
||||
marker. Cleared wholesale on TOTP disable / password change / password reset.
|
||||
|
||||
### shard_ruleset — the shard's published ruleset (Protocol 3.0)
|
||||
|
||||
Singleton row (`id = 1`, CHECK-constrained) holding the latest `world.ruleset` frame: `rev`,
|
||||
`expansion`, `payload` JSON (the whole frame), `t`, `updated_at`. The shard re-emits the complete
|
||||
ruleset on every sidecar connect, so this is an **overwrite, not an append** — and the kind is
|
||||
deliberately **not** in `LOGGED_KINDS`, since logging it would put a duplicate row in `shard_events`
|
||||
on every reconnect while `server.hello` already marks each of those.
|
||||
|
||||
The frame is stored whole rather than normalized into columns: it is a flat description of server
|
||||
config that is read as one page, so splitting it up would mean a schema change every time the shard
|
||||
grows a new block. `rev` (the shard's FNV-1a of the body) and `expansion` are hoisted only because
|
||||
they are cheap to display — the same payload-plus-hoisted-columns shape `shard_champs` uses.
|
||||
|
||||
**No row means the shard has never published one** (an older plugin, or `Bridge.RulesetEnabled=false`),
|
||||
served as `null` rather than `{}`: "not published yet" and "published, everything off" are different
|
||||
answers and the page renders them differently.
|
||||
|
||||
### shard_feature_visibility — per-feature audience config (Protocol 3.0)
|
||||
|
||||
One row per shard feature: `feature` (PK), `enabled`, `audience` (a rung on the ladder in §6.5),
|
||||
@@ -569,6 +586,7 @@ from the per-route **siteMode** middleware (§5), never from an auth gate.
|
||||
| GET | `/wiki` | list of pages (slug + title) |
|
||||
| GET | `/wiki/:slug` | single page |
|
||||
| POST | `/contact` | (rate-limited) send mail via SMTP; if unconfigured, respond `{fallback:"mailto", email}` |
|
||||
| GET | `/shard/ruleset` | the shard's own published ruleset (Protocol 3.0 `world.ruleset`): expansion, which optional systems are on, skill/stat caps, account and house limits, champion scroll rules, the save/restart schedule. Served from `shard_ruleset`, so it renders while the shard is down; live via `world.ruleset` on `/shard/stream`. Behind `requireFeature('ruleset')`. **`null`** means the shard has never published one — a real answer, distinct from a published ruleset. `caps.skill` / `caps.totalSkill` are in **tenths** (1000 = 100.0). |
|
||||
| GET | `/shard/features` | the shard features **this caller** may reach plus the audience rung they resolved to (§6.5), so a client hides nav it can't follow. Reports only what the caller can see — the list itself never discloses a gated feature. Consumed by the SPA header and (pending) the Android nav. |
|
||||
|
||||
Public content GETs pass through the **siteMode** gate (§5).
|
||||
|
||||
Reference in New Issue
Block a user