docs(link): the Protocol 3.0 cutover (v3.md order 6)
INTEGRATION.md was written for the window that just closed -- it told integrators the version had NOT been bumped yet and that a sidecar on `edge` reports 2 while already carrying v3 kinds. That guidance is now wrong in the direction that matters, so the version section states 3 (header, /health, ws.hello, the 409 example and the §8 worked example) and replaces the "until then" paragraph with what a v2 integration actually has to do to upgrade: change the constant it sends, and nothing else, because nothing that existed in v2 changed shape. v3.md gains §4.1 for what the bump touches and, more importantly, WHY the website's boot migration is gated on a marker row: schema.sql is re-run on every boot and uo_link_config.protocol is admin-editable, so an ungated UPDATE would silently un-pin an operator running an older sidecar. That is the one piece of the cutover a reader could not infer from the code being one constant. Progress tables: 5b done, 6 in review. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
43
link/v3.md
43
link/v3.md
@@ -1,6 +1,6 @@
|
||||
# Protocol 3.0 — Shard content, standings & the visibility framework
|
||||
|
||||
**Status:** In progress. All work lands on an `edge` branch in each repo; `edge` → `main` is the v3 cutover.
|
||||
**Status:** Feature-complete on `edge`; the cutover (order 6) is in review. All work lands on an `edge` branch in each repo; `edge` → `main` is the v3 cutover.
|
||||
**Date:** 2026-07-28
|
||||
**Codebase:** ServUO 57.4, `<servuo>`, net48 / x64, Expansion **EJ**.
|
||||
**Companion to** [`PLAN.md`](PLAN.md) (1.0 read/event plane), [`PROTOCOL_2.md`](PROTOCOL_2.md) (2.0 provisioning + world-state streams), [`ADMIN_CONTROLS.md`](ADMIN_CONTROLS.md) (staff write plane), [`INTEGRATION.md`](INTEGRATION.md) (website API).
|
||||
@@ -16,8 +16,8 @@ Each part is marked off here as it lands on `edge`. §9 carries the same state p
|
||||
| 3 | **C** — spawn atlas (§6) | ✅ **Done** | website [#112](https://gitea.whitlocktech.com/RunicGateway/website/pulls/112) (parsers + CLI + tables) + [#113](https://gitea.whitlocktech.com/RunicGateway/website/pulls/113) (API + pages + admin panel), docs [#67](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/67) + [#68](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/68) |
|
||||
| 4 | **B/2** — `points.board` (§7) | ✅ **Done** | servuo-plugins [#4](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins/pulls/4), link [#18](https://gitea.whitlocktech.com/RunicGateway/link/pulls/18), website [#114](https://gitea.whitlocktech.com/RunicGateway/website/pulls/114), docs [#69](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/69) |
|
||||
| 5a | **B/3 dependency** — cliloc table (§8.6) | ✅ **Done** | website [#115](https://gitea.whitlocktech.com/RunicGateway/website/pulls/115), docs [#70](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/70) |
|
||||
| 5b | **B/3** — `vendor.listing` (§8) | 🟨 In review | servuo-plugins [#5](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins/pulls/5), link [#19](https://gitea.whitlocktech.com/RunicGateway/link/pulls/19), website [#116](https://gitea.whitlocktech.com/RunicGateway/website/pulls/116), docs [#71](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/71) |
|
||||
| 6 | **Cutover** — `PROTOCOL_VERSION` 2→3 (§4) | ⬜ Not started | — |
|
||||
| 5b | **B/3** — `vendor.listing` (§8) | ✅ **Done** | servuo-plugins [#5](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins/pulls/5), link [#19](https://gitea.whitlocktech.com/RunicGateway/link/pulls/19), website [#116](https://gitea.whitlocktech.com/RunicGateway/website/pulls/116), docs [#71](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/71) |
|
||||
| 6 | **Cutover** — `PROTOCOL_VERSION` 2→3 (§4) | 🟨 In review | the bump: link [#PR_LINK_BUMP](https://gitea.whitlocktech.com/RunicGateway/link/pulls/PR_LINK_BUMP), website [#PR_SITE_BUMP](https://gitea.whitlocktech.com/RunicGateway/website/pulls/PR_SITE_BUMP), docs [#PR_DOCS_BUMP](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/PR_DOCS_BUMP) — then `edge` → `main`: servuo-plugins [#PR_PLUG_CUT](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins/pulls/PR_PLUG_CUT), link [#PR_LINK_CUT](https://gitea.whitlocktech.com/RunicGateway/link/pulls/PR_LINK_CUT), website [#PR_SITE_CUT](https://gitea.whitlocktech.com/RunicGateway/website/pulls/PR_SITE_CUT), docs [#PR_DOCS_CUT](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/PR_DOCS_CUT) |
|
||||
|
||||
Order 5 split in two once §8.6's cliloc dependency turned out to be a client-format problem rather
|
||||
than a parser (see §8.6). 5a is website-only and lands first so the marketplace ships with real item
|
||||
@@ -242,6 +242,39 @@ admin-set `uo_link_config.protocol` column — so it happens **exactly once**, a
|
||||
from 2 to 3, so the cutover doesn't require a manual admin edit. `UOLINK_PROTOCOL` still overrides.
|
||||
- No feature-negotiation array anywhere — v3 implies all three kinds.
|
||||
|
||||
### 4.1 What the bump actually touches
|
||||
|
||||
The version lives in five places, and all five move together:
|
||||
|
||||
| Where | Change |
|
||||
|---|---|
|
||||
| `link/sidecar/src/main.rs` | `PROTOCOL_VERSION` 2 → 3 (with the v3 note beside the v2 one), plus the sidecar README's worked example |
|
||||
| `website/server/db/schema.sql` | `uo_link_config.protocol` column default 1 → 3, plus the boot migration below |
|
||||
| `website/server/src/model/uoLinkConfig/uoLinkConfig.model.js` | `DEFAULT_PROTOCOL` — what a site with nothing saved yet declares |
|
||||
| `website/server/src/utils/uoLinkClient.js` + `uoLinkSocket.js` | the `config.protocol || …` fallbacks, so an unset value can never quietly send `1` and 409 with a confusing message |
|
||||
| `website/client/.../ShardAdmin.jsx`, `website/.env.example` | the admin form's initial value and the documented env default |
|
||||
|
||||
**The migration has to be one-shot, and that is the only subtle part.** `schema.sql` is re-run on
|
||||
*every* boot (`utils/db.js::ensureSchema`), and every other statement in its migration block is an
|
||||
idempotent `ADD COLUMN IF NOT EXISTS` / `MODIFY`. A bare `UPDATE uo_link_config SET protocol = 3`
|
||||
would not be idempotent in the sense that matters: `protocol` is **admin-editable**, so an operator
|
||||
who deliberately pins an older sidecar in Admin → Shard would silently be un-pinned on the next
|
||||
restart. It is therefore gated on a marker row in `settings`:
|
||||
|
||||
```sql
|
||||
ALTER TABLE uo_link_config MODIFY COLUMN protocol INT NOT NULL DEFAULT 3;
|
||||
UPDATE uo_link_config SET protocol = 3
|
||||
WHERE id = 1 AND protocol < 3
|
||||
AND NOT EXISTS (SELECT 1 FROM settings WHERE `key` = 'uo_link_protocol_3_migrated');
|
||||
INSERT IGNORE INTO settings (`key`, value) VALUES ('uo_link_protocol_3_migrated', '1');
|
||||
```
|
||||
|
||||
The marker is written *after* the `UPDATE`, so the first boot on the new build migrates and every
|
||||
later boot is a no-op. A fresh install has no `uo_link_config` row to update and simply gets the
|
||||
marker plus the new column default. `protocol < 3` rather than `= 2` so an install that never left
|
||||
the old default of `1` is carried across too — it could not have been talking to a v2 sidecar
|
||||
anyway.
|
||||
|
||||
---
|
||||
|
||||
## 5. Part B/1 — `world.ruleset` ✅ Done
|
||||
@@ -887,8 +920,8 @@ not a blocker here.)
|
||||
| 3 | **C** — spawn atlas (§6) | website, docs | none | ✅ Done |
|
||||
| 4 | **B/2** — `points.board` (§7) | all four | new kind + `char.profile` field | ✅ Done |
|
||||
| 5a | **B/3 dependency** — cliloc table (§8.6) | website, docs | none | ✅ Done |
|
||||
| 5b | **B/3** — `vendor.listing` (§8) | all four | new kinds | 🟨 In review |
|
||||
| 6 | **Cutover** — `PROTOCOL_VERSION` 2→3, `edge` → `main` | all four | the bump | ⬜ |
|
||||
| 5b | **B/3** — `vendor.listing` (§8) | all four | new kinds | ✅ Done |
|
||||
| 6 | **Cutover** — `PROTOCOL_VERSION` 2→3, `edge` → `main` | all four | the bump | 🟨 In review |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user