From 756c13d47b449e83e7e8783f1f65750910141ed3 Mon Sep 17 00:00:00 2001 From: wtclaude Date: Mon, 12 Oct 2026 02:48:12 -0500 Subject: [PATCH] =?UTF-8?q?docs(rust):=20protocol=2014=20=E2=80=94=20kits.?= =?UTF-8?q?uses=20and=20reward=20notices=20(PROTOCOL=20=C2=A720,=20PLAN=5F?= =?UTF-8?q?REDESIGNS=20=C2=A72.9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wire half of PLAN_REDESIGNS §2 (D332, D333): PROTOCOL.md §2 says 14, and §20 specifies kits.uses (counts only, bounded by the sync's bound, POST /kits/uses) and perm.sync notices (the whole untold set, told once when the player is awake, told keys kept on disk, noticesTold in the report). PLAN_REDESIGNS §2.9 records the Rust half as built and its compile on both rigs. Stacked on docs/event-step-editor (docs#335) for §2.8. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY --- modules/rust/PLAN_REDESIGNS.md | 26 ++++++++++++++ rust-link/PROTOCOL.md | 65 +++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/modules/rust/PLAN_REDESIGNS.md b/modules/rust/PLAN_REDESIGNS.md index ce412c4..86b3023 100644 --- a/modules/rust/PLAN_REDESIGNS.md +++ b/modules/rust/PLAN_REDESIGNS.md @@ -409,6 +409,32 @@ Everything in §2.1–§2.3 and §2.5's core half, with three things settled whi registers its 12 actions), the server suite 723/723 and the client suite 45/45 — the same numbers as 1.11.0's. The Module-Rust half (the kit weekend, `linked`, `kits.uses`, the reward message) follows on `edge`. +### 2.9 As built: the Rust half, protocol 14 (2026-10-12) + +Branches `feat/protocol-14-step-editor` in Rust-Plugins, Rust-Link and Module-Rust, into `edge`; the wire is +`rust-link/PROTOCOL.md` §20. + +- **The kit weekend** is `rust.template.kit_weekend`: inputs kit, minutes (a duration), message and delivery. + It reads the kit from its server when it is filled in, so the lease names the kit's real permission. A kit + with no permission is open to everyone already and gets step 2 alone; a kit with no use limit has no + "one more use" and gets step 1 alone. The phase is the weekend: `advance: { after }` equals the minutes. + Run through the real 1.13.0 core (website#212), it registers, and the plan it builds validates as a spec. +- **`linked`** is "every linked account that has played on this server" — a stats row there — because a link + is fleet-wide and the server is what narrows it. It reads no tally, and past the server's recipient bound it + is refused with the bound's name (`EventsMaxRecipients`), never trimmed. +- **The reward message** is checked with the kit's name in place of `{kit}`, against the chat bound, so a + long kit name cannot push past what the game will say. It is stored on each grant row + (`rust_perm_run_grants.notice`, `notice_delivery`, `notice_told_at`). +- **The kit warning** is the `note` on `rust.options.grouppermissions` rows. That source is searchable, so the + editor may not hold the chosen row; core asks for that one value when it needs its note (website#212). +- **Timed params:** `rust.zone.open` and `rust.participation.open` declare `minutes` a duration, and the + group-permission lease gives `true` as its value example. +- **Compiled on both rigs, 2026-10-12.** Carbon 2.0.262 on Rust 25823813 (the latest of both): the bridge + compiled and loaded in 3.8 s, protocol 14, its told-notices store read at load. Oxide 2.0.7820 on the same + Rust build (the rig was behind on both, and was updated first: its first restart's steamcmd update did not + finish, the second did): compiled in 5.3 s and loaded. Both rigs were put back on their protocol-13 bridge afterwards, to match their sidecars until + the end-of-plan walk sets up protocol 14 (D331). + --- ## 3. Zones: ZoneManager's options, and a dome (§4.4; D166, D167) diff --git a/rust-link/PROTOCOL.md b/rust-link/PROTOCOL.md index 81fe256..b20553f 100644 --- a/rust-link/PROTOCOL.md +++ b/rust-link/PROTOCOL.md @@ -50,7 +50,7 @@ it is listening without one. ## 2. Versioning -The wire version is a single integer — **13** as of the first player walk's fixes (§19) — declared in +The wire version is a single integer — **14** as of the step editor (§20) — declared in **four** places that must agree: | Where | Repo | @@ -2638,3 +2638,66 @@ unaffected. The refusal is checked before anything is spawned, with the two reas The site checks the same thing first, from the hello's `integrations.runicNpc`, and refuses the step before it is sent; the bridge's check is for a site that missed the hello. `rg.npc` says the same when RunicNPC is not loaded. + +--- + +## 20. Protocol 14 — the step editor + +Opened by [`PLAN_REDESIGNS.md`](../modules/rust/PLAN_REDESIGNS.md) §2 after protocol 13 shipped with RunicNPC +v1.0.0 (D332). It is built on `edge` in Rust-Plugins, Rust-Link and Module-Rust and released once, after the +end-of-plan walk (D331); the first-class optional plugins (§11 there) join it. **This section grows as the +pieces land.** `PROTOCOL_VERSION` becomes 14 in all four places (§2). + +### 20.1 `kits.uses` — how many have used a kit up (§2.6) + +The warning beside a kit weekend: *"Kit vip: 2 uses, 24 h cooldown — 9 of 41 linked players have used it up."* +The website asks about the players it already knows — the linked players of the server — and the answer is +**counts, never a list**. + +```json +{"cmd":"kits.uses","reqId":"r-12","kit":"vip","steamIds":["76561190000000001","76561190000000002"]} +{"kind":"kits.uses","type":"reply","reqId":"r-12","kit":"vip","max":2,"cooldown":86400,"asked":2,"exhausted":1,"onCooldown":0} +``` + +- **Main thread**, two Kits reads per player (`GetPlayerKitUses`, `GetPlayerKitCooldown`), plus `GetKitMaxUses` and + `GetKitCooldown` once. `exhausted` counts players whose uses have reached `max`; a kit with no use limit + (`max` 0) is never used up. `onCooldown` counts players with any cooldown remaining. `asked` is how many ids + parsed. +- **Bounded by the sync's own bound** (`PermMaxOps`, 20,000): the site sends no more players than a sync + carries. +- Refusals are `kits.error`, as for `kits.list`: `kits-missing` (Kits is not loaded), `unknown-kit`, + `too-large`. +- **The sidecar route is `POST /kits/uses`**, a thin forward like `/kits`; the list rides in the body because it + can be as long as a server's linked players. Nothing is kept. +- **The website** asks once per kit that a permission gates, per server, at most 25 kits, and keeps the answer + a minute. It attaches the sentence as the `note` of every `rust.options.grouppermissions` row whose + permission is that kit's (core's option note, MODULE_API 1.13.0). A failure is no note. + +### 20.2 `notices` on `perm.sync` — the reward's message (§2.4, D333) + +"You earned kit vip — type /kit vip", said once to the player a reward step picked. `rust.kit.entitle` gains an +optional `message` and `delivery`; the site writes them on each grant row, and every sync carries the rows' +**whole untold set** for that server, beside `credits`: + +```json +{"cmd":"perm.sync", …, "notices":[{"key":"7:3:11","steamId":"76561190000000001","message":"You earned kit vip — type /kit vip","delivery":"popup"}]} +``` + +- **`key`** is `::`: one reward step tells one person once, whichever of their linked + accounts it picked. **`steamId`** is that account, while it is still linked to the person. +- **When it is said is the plugin's.** At the end of the sync, to a player who is connected and **awake** — + a sleeping or loading player sees no popup and reads no chat — and otherwise on `OnPlayerSleepEnded`, the + next time they wake on this server. A popup goes through PopupNotifications when `delivery` is `popup` and + the plugin is loaded, and chat otherwise; the reward was granted long before this moment, so the player is + told either way. At most 2,000 notices per sync; a message is cut at the chat bound (`EventsMaxChat`). +- **Told keys are kept on disk** (`data/RunicGateway/notices.json`) until the site stops sending them, so a + reload between telling a player and the report that says so cannot tell them twice. Each sync forgets every + told key the set no longer carries. +- **The report lists them back**: `perm.report` gains `noticesTold`, every key of this sync's set that has been + told — at this sync or before it. Present only when the sync carried `notices`, like the credit counts. The + site marks those rows told, and they leave the next sync's set. +- **A withdrawn reward takes its message with it.** Teardown deletes the grant row, so the notice leaves the set + untold, and nobody is told about a reward that is no longer theirs. +- **Absent is not empty**, as for `credits`: a sync with no `notices` field leaves the plugin's set alone. The + site sends the field on every sync from protocol 14, empty when there is nothing to say. The notices are part + of the sync's digest, so a new one is pushed at once.