Merge pull request 'docs(rust): plan permission rewards — lend or give any registered permission (PLAN_REDESIGNS §12, D342–D346)' (#342) from docs/rust-perm-rewards-plan into main
Reviewed-on: #342
This commit is contained in:
@@ -10,7 +10,8 @@ rows still to come (§3.4); §4, built 2026-09-29 (§4.1). **§6 was spiked on 2
|
||||
chose neither route: Runic Gateway writes its own NPC plugin, RunicNPC, planned in
|
||||
[`../../runicnpc/PLAN.md`](../../runicnpc/PLAN.md) (D214–D314), and the rest of this plan waits for it.** RunicNPC v1.0.0 shipped on 2026-10-09, and the plan
|
||||
resumed with §2 the same day (D331–D334); §2 was built on 2026-10-12, and §11's Economics spike the same day
|
||||
raised D335–D336 (§11.2.1). Economics was built on 2026-10-12 too (§11.2.4). The Backpacks spike followed and raised D337–D339 (§11.3.1), and Backpacks was built the same day (D340, D341, §11.3.4). **Every item left is built, tested and PR'd first; every walk —
|
||||
raised D335–D336 (§11.2.1). Economics was built on 2026-10-12 too (§11.2.4). The Backpacks spike followed and raised D337–D339 (§11.3.1), and Backpacks was built the same day (D340, D341, §11.3.4). The org lead then added permission rewards (§12,
|
||||
D342–D346), planned the same day. **Every item left is built, tested and PR'd first; every walk —
|
||||
theirs and the ones still owed by §3 and §5 — happens together at the end (D331, §9).**
|
||||
|
||||
This is a companion to [`PLAN_FIXES.md`](PLAN_FIXES.md) and [`PLAN.md`](PLAN.md). Where they disagree, this
|
||||
@@ -25,6 +26,7 @@ document is later and wins. Its decisions continue PLAN_FIXES' numbering at **D1
|
||||
| 5 | Chat titles: twenty-three conditions | §4.6, D172–D175 | Rust-Plugins, Module-Rust |
|
||||
| 6 | NPCs — now RunicNPC, its own plan ([`runicnpc/PLAN.md`](../../runicnpc/PLAN.md)) | §4.7 | **runicnpc-rust**, Rust-Plugins, Rust-Link, Module-Rust, installer |
|
||||
| 11 | First-class optional plugins: Economics, Backpacks, RaidableBases (Kits stays required) | — (added 2026-09-28) | Rust-Plugins, Module-Rust, installer, Android-app |
|
||||
| 12 | Permissions as event rewards: until the event ends, or for good | — (added 2026-10-12) | **core** (website `main`, MODULE_API 1.14.0), Module-Rust |
|
||||
|
||||
**Protocol.** §1, §3, §4 and §5 joined **protocol 13**, which shipped on 2026-10-09 with RunicNPC v1.0.0
|
||||
(bundle 2026.10.09). The wire changes still to come, §2's and §11's, **open protocol 14** on `edge` and are
|
||||
@@ -1015,6 +1017,8 @@ module does not have, and R9 keeps item icons out of the asset bridge.
|
||||
| **D340** | **A backpack slot shows the item's name, not an icon.** The plugin sends each stack's English name from the game (`display`), so "Wood ×1000" and "Assault Rifle + Weapon Lasersight" need no item catalogue and nothing loads from outside the site. R9 stands. | Icons from a third-party host keyed by shortname; shortnames alone. | 11.3.4 |
|
||||
| **D341** | **A blueprint names what it makes.** Backpacks stores a blueprint as `blueprintbase` with a target; the stack carries `blueprint` (the target's shortname), its `display` is the target's name, and the slot reads "Assault Rifle blueprint". | Every blueprint shown as the same anonymous "Blueprint". | 11.3.4 |
|
||||
|
||||
Permission rewards, added on 2026-10-12, were decided as D342–D346; they are tabled with their section, in §12.8.
|
||||
|
||||
## 11. First-class optional plugins (D199–D202)
|
||||
|
||||
The org lead named four plugins the module supports as first-class integrations. Kits already is one. The other
|
||||
@@ -1646,3 +1650,167 @@ The org lead answered §11.4.4's three questions the same day:
|
||||
|
||||
These are new verbs, events and hello fields. **They join protocol 14 (D332)**, which §2 opens: protocol 13
|
||||
shipped on 2026-10-09, before §9 reached item 7.
|
||||
|
||||
---
|
||||
|
||||
## 12. Permissions as event rewards (D342–D346)
|
||||
|
||||
The org lead asked for this on 2026-10-12, during the Backpacks build: an event reward that grants **any
|
||||
permission the server's plugins registered**, so a perk nobody planned for (night vision, a chat colour, a
|
||||
`/remove` command) is a reward without code written for it. The picker sorts by mod, then by permission
|
||||
inside the mod. It is its own item, after Backpacks, and planned first. Five decisions, D342–D346, were answered
|
||||
the same day (§12.8).
|
||||
|
||||
Two steps come out of it. **Permissions until the event ends** lends them for the run, as a kit reward does.
|
||||
**Permissions for good** gives them for keeps, as a staff member's grant in the permission manager does. Both
|
||||
take several permissions in one step, which needs one small addition to core's step editor (§12.3).
|
||||
|
||||
### 12.1 What it builds on
|
||||
|
||||
Nothing below is new machinery; both steps are rows in tables the permission manager already pushes.
|
||||
|
||||
- **The lease is a kit reward's** (PLAN.md §29, D84). `rust.kit.entitle` and `rust.backpack.size` (D337) write
|
||||
one `rust_perm_run_grants` row per recipient, the permission mirror pushes it in the next `perm.sync`, and the
|
||||
step's revert deletes the rows so the next sync revokes them. The push reads the **union** of these rows and
|
||||
the standing grants, so a player who already held the permission keeps it after the revert.
|
||||
- **A standing grant is the permission manager's own** (§1): a `rust_perm_grants` row for a website user,
|
||||
scoped to a server, reaching every account the user has linked (D28). It is `UNIQUE` on (user, permission,
|
||||
scope), so granting one twice leaves the first.
|
||||
- **The catalogue** is `rust_perm_catalogue`: per server, every registered permission and the plugin that
|
||||
registered it (`owner`, the plugin's `Name`). A permission no plugin owns, as Carbon's built-in modules
|
||||
register theirs, has no owner, and the permission manager groups it by its prefix (§1).
|
||||
- **The message is D333's notice**, which rides `perm.sync` and is told once, at once or on the player's
|
||||
next wake.
|
||||
- **So there is no plugin code, no sidecar code and no protocol change.** Protocol 14 is untouched.
|
||||
|
||||
### 12.2 The picker: `rust.options.permissions` (D342)
|
||||
|
||||
- **Every permission in the catalogue of every enabled server, once each.** Its `group` is the plugin that
|
||||
registered it. A permission with no owner is grouped by its prefix, labelled *"<prefix> (not
|
||||
registered by a plugin)"*, the same rule the permission manager draws.
|
||||
- **Sorted by group, then by permission inside the group**, both case-insensitively. The editor keeps a
|
||||
source's order.
|
||||
- **A row says where it is missing.** A permission that is not in every enabled server's catalogue carries
|
||||
a row `note` (MODULE_API 1.13.0): *"Only on Main, PvP"*.
|
||||
- **Not `searchable`.** A server registers a few hundred permissions; the multi-select's own filter box
|
||||
(§12.3) narrows them in the browser. If a deployment ever passes the 2,000-row bound, the source says so, as
|
||||
every bounded source does.
|
||||
- **No blocklist and no allowlist** (D343). The bridge's own `runicgateway.*` permissions are in the list like
|
||||
any other.
|
||||
- **The step checks the server it is given.** Every picked permission must be in that server's catalogue; one
|
||||
that is not is refused by name: *"PvP has no permission nightvision.allowed — its plugins did not register
|
||||
it"*. The check runs in the dry run too.
|
||||
|
||||
### 12.3 The core addition: a param that holds several values (D344, MODULE_API 1.14.0)
|
||||
|
||||
The step editor has six param types, all single values. A step that takes several permissions needs a
|
||||
list, so core gains one declaration flag. **It is an addition only**: a module that does not use it is
|
||||
unchanged, and Module-uo's `coreApi: "^1.10.0"` still resolves.
|
||||
|
||||
- **`multiple: true` on an action param** of type `string` or `int`, with an optional `max` (1 to 100, 20 if
|
||||
left out). It is refused on any other type, on a `duration` param, and on a template's inputs, which this
|
||||
version does not extend.
|
||||
- **The value is a JSON array**: each element checked as the type's literal, duplicates dropped, order kept, at
|
||||
most `max`. `required` means at least one. A bare value is read as a list of one, so a spec written by hand
|
||||
or over the API does not trip on it. The module's `perform()` and `cost()` receive the array.
|
||||
- **The catalog serves `multiple` and `max`** beside the rest of the declaration (`GET
|
||||
/admin/events/catalog`).
|
||||
- **The editor draws a multi-select.**
|
||||
- With a `source`: the chosen values as chips above a grouped checklist, with a filter box over it. Ticking
|
||||
past `max` is refused with the number.
|
||||
- With a `searchable` source: the typeahead adds a chip per pick.
|
||||
- With no source: a tag box, a value per Enter.
|
||||
- **The definition view and the run console** show a list as its values joined by commas.
|
||||
- **Docs:** `website/MODULE_API.md` gains 1.14.0's entry and the flag in the declaration reference;
|
||||
`website/EVENTS.md` §F names the control.
|
||||
|
||||
### 12.4 Permissions until the event ends: `rust.perm.lend` (D345, D346)
|
||||
|
||||
*"Lends the permissions you pick to the people a mode picks from this run's tally — or every linked player of
|
||||
the server — until the run ends. Waits for them if they are offline. Someone who already held one keeps it
|
||||
when the event ends."*
|
||||
|
||||
- **Params:**
|
||||
- the server;
|
||||
- the permissions (`multiple`, `max` 10, from §12.2);
|
||||
- the recipients and count (`rust.kit.entitle`'s modes, `linked` included);
|
||||
- a message and its delivery;
|
||||
- **`confirm`**, a required boolean: *"I am sure I want to give these permissions as a reward"* (D343).
|
||||
- **One row per recipient per permission** in `rust_perm_run_grants`, with no kit and no credit; the notice
|
||||
goes on one row per recipient, so each is told once.
|
||||
- **Unticked, it refuses** in the dry run and at run time, naming what it would have given: *"Tick "I am sure"
|
||||
to make nightvision.allowed, betterchat.color a reward"*. Being a required toggle (D334), it cannot be left
|
||||
unset.
|
||||
- **`risk: 'change'`, `reversible: 'ledger'`**, as a kit reward is. Its revert and reconcile are
|
||||
`rust.kit.entitle`'s, and core reverts it at the end of every run, a normal finish included.
|
||||
- **The budget is new: `rust.permissions`, *Permissions lent*.** One per recipient per permission; a mode
|
||||
that is not a count is priced at the recipient bound times the permissions, as kit rewards are.
|
||||
|
||||
### 12.5 Permissions for good: `rust.perm.give` (D345, D346)
|
||||
|
||||
*"Gives the permissions you pick to the people a mode picks, for good. Ending or cancelling the event does not
|
||||
take them back; staff remove them in the permission manager."*
|
||||
|
||||
- **The same params as §12.4**, the confirm included.
|
||||
- **A standing grant per website user per permission**, scoped to the step's server, with source `event` and
|
||||
the note *"event run <run>, step <step>"*. A grant already there is left alone and counted as
|
||||
*already held*.
|
||||
- **`risk: 'irreversible'`, `reversible: 'none'`**, as `rust.coins.pay` is (D335). Like every step that changes
|
||||
the world it arrives off until an admin turns it on under Actions; unlike §12.4's, its failure aborts the run
|
||||
by default instead of pausing it, and Actions lists it as irreversible, so an admin enables the two
|
||||
separately.
|
||||
- **The budget is new too: `rust.permissions.kept`, *Permissions given for good***, priced as §12.4's.
|
||||
- **Taking one back is the permission manager's.** The grant shows there with its source and note, and staff
|
||||
delete it like any other.
|
||||
- **The message rides a notice-only row** in `rust_perm_run_grants`: no permission, no kit, no credit. The
|
||||
push grants nothing for it and tells the notice once. Nothing reverts the step, so the row stays; it is a
|
||||
sentence that has been said.
|
||||
|
||||
### 12.6 Settled in this plan, and overrulable
|
||||
|
||||
- **A blank message tells nobody**, as a kit reward's does (D333), rather than a default sentence. A
|
||||
permission's name (`nightvision.allowed`) means nothing to a player, so only the author can say what it does:
|
||||
*"You can use /nv until the event ends"*. `{permissions}` puts the names in.
|
||||
- **At most 10 permissions in one step**: enough for a perk bundle, and the price stays readable.
|
||||
- **A permission the server's catalogue lacks is refused, not skipped.** The plugin may be unloaded for the
|
||||
wipe, and a reward that silently gives less than it says is the worse failure.
|
||||
- **The for-good grant is scoped to the step's server**, not every server. An author who wants it everywhere
|
||||
adds a step per server.
|
||||
|
||||
### 12.7 Where the work lands, and in what order
|
||||
|
||||
1. **Website (core), on `main`:** §12.3, MODULE_API **1.13.0 → 1.14.0**, with its tests (`registries`,
|
||||
`spec`, the editor's multi-select) and Module-uo's frozen-manifest proof against the new core, as 1.11.0's and
|
||||
1.13.0's were run.
|
||||
2. **Module-Rust, on `edge`**, after the website PR merges: the option source, the two actions, the two
|
||||
budgets; `coreApi` `^1.14.0`; `ci/core-ref.json` re-pinned to the merge; `routes.manifest` regenerated.
|
||||
3. **docs:** this section's *Built* notes; `website/MODULE_API.md`; `website/EVENTS.md`.
|
||||
|
||||
**Not touched:** Rust-Plugins, Rust-Link, the protocol, the installer, Android-app (the app does not author
|
||||
events) and Module-uo. The Integration Kit's pin is at 1.12.0 and moves only when someone re-reads its
|
||||
chapters for a newer core; it skipped 1.13.0 the same way.
|
||||
|
||||
### 12.8 Decisions of record
|
||||
|
||||
Answered by the org lead on 2026-10-12.
|
||||
|
||||
| # | Decision | Rejected | § |
|
||||
|---|---|---|---|
|
||||
| **D342** | **An event reward may be any permission the server's plugins registered**, picked from the catalogue grouped by the plugin that registered it and sorted by plugin, then permission. `rust.backpack.size` stays beside it, with its sizes and its take-back warning. | A fixed list of perks; folding the backpack step into the generic one. | 12.2 |
|
||||
| **D343** | **No blocklist and no allowlist. The safety is a required "I am sure" toggle in the step**; unticked, the dry run and the run refuse, naming the permissions. | A pop-up when the step is saved (a core change); a blocklist of dangerous permissions. | 12.2, 12.4 |
|
||||
| **D344** | **One step gives several permissions, through a multi-select picker**: a `multiple` flag on an action param, added to core as MODULE_API 1.14.0. | One permission per step; five fixed picker slots; a comma-separated text box. | 12.3 |
|
||||
| **D345** | **A permission reward lasts until the run ends, or for good**, the author's choice. | Until the run ends only. | 12.4, 12.5 |
|
||||
| **D346** | **The two durations are two steps**, `rust.perm.lend` (`change`) and `rust.perm.give` (`irreversible`), each with its own budget, because core gives an action one risk class. | One step with a "keep it" switch, rated `irreversible` throughout. | 12.4, 12.5 |
|
||||
|
||||
### 12.9 The walk (deferred to the end, D331)
|
||||
|
||||
On both rigs, with a plugin that registers a perk (NightVision or similar):
|
||||
|
||||
- open the picker and see it grouped by plugin, sorted inside each, a permission missing from a server noted,
|
||||
and the unowned ones grouped by prefix;
|
||||
- run a *Permissions until the event ends* step with two permissions, unticked (refused) and ticked; see the
|
||||
perks work online and offline at the grant, and gone after the run ends, except for a player who already held
|
||||
one;
|
||||
- run a *Permissions for good* step; see it stay after the run ends, show in the permission manager with its
|
||||
note, and go when staff delete it;
|
||||
- unload the plugin and see the step refuse the permission by name.
|
||||
|
||||
Reference in New Issue
Block a user