docs(rust): console commands built — command.run (PROTOCOL §20.11, PLAN_REDESIGNS §16.10, D385)
- rust-link/PROTOCOL.md §20.11: command.run in its three shapes (once with a
stored teardown, per online recipient with {steamid}/{name}, teardownOf),
the at-most-once key file, the frame budget, command.ran / command.error
and their reasons, how unknown-command is told (the game's log line, not
Run's return), POST /commands/run, and the website side.
- modules/rust/PLAN_REDESIGNS.md: D385 (the bridge keeps a step's teardown
with its key, asked during the build), §16.10 the build record (three
spike findings, the rig run, twelve settled-in-code points), a D385 walk
row in §16.9, pointers from the status paragraph, §9 and §10.
- website/EVENTS.md: an action can be text the module cannot read: what
core already bounds, and the two things a module copying it needs (a
failed step's revert has only the key; `multiple` drops duplicates).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -11,7 +11,7 @@ chose neither route: Runic Gateway writes its own NPC plugin, RunicNPC, planned
|
||||
[`../../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). The org lead then added permission rewards (§12,
|
||||
D342–D346), planned and built the same day. On 2026-10-14 RaidableBases was deferred until the current paid copy arrives (D347), with both editions to be supported (D348, §11.4.2). The same day the org lead added Rust's own world events to the base module (§13, D349) and six more first-class optional plugins (§14, D350–D352), to be tested together in one phase before their integration plan. Their questions were answered the same day (D353–D359, the end walk now waiting for RaidableBases), and Steam sign-in stays on the website's plan, linked as §15 (D360). **The §14.2 test phase ran the same day on both rigs (§14.2.1)**: the org lead ruled D361–D362 during it and answered its Q19–Q25 the same day (D363–D369). On 2026-10-16 the org lead added console commands as event steps and rewards (§16, D382–D384), to be built before RaidableBases. **Every item left is built, tested and PR'd first; every walk —
|
||||
D342–D346), planned and built the same day. On 2026-10-14 RaidableBases was deferred until the current paid copy arrives (D347), with both editions to be supported (D348, §11.4.2). The same day the org lead added Rust's own world events to the base module (§13, D349) and six more first-class optional plugins (§14, D350–D352), to be tested together in one phase before their integration plan. Their questions were answered the same day (D353–D359, the end walk now waiting for RaidableBases), and Steam sign-in stays on the website's plan, linked as §15 (D360). **The §14.2 test phase ran the same day on both rigs (§14.2.1)**: the org lead ruled D361–D362 during it and answered its Q19–Q25 the same day (D363–D369). On 2026-10-16 the org lead added console commands as event steps and rewards (§16, D382–D384), to be built before RaidableBases; **they were built the same day (§16.10)**, with D385. **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
|
||||
@@ -935,7 +935,8 @@ pulls) is research, not a walk, so it still comes first:
|
||||
2026-10-16 (D381).** **Stage 9, core's trigger starts, was built on 2026-10-16 (§14.3.21)**, which ends the
|
||||
build.
|
||||
10. **Console commands as event steps and rewards** (§16, D382–D384), added on 2026-10-16: one stage across
|
||||
Rust-Plugins, Rust-Link and Module-Rust (§16.8), built before RaidableBases.
|
||||
Rust-Plugins, Rust-Link and Module-Rust (§16.8), built before RaidableBases. **Built on 2026-10-16 (§16.10)**,
|
||||
with D385.
|
||||
|
||||
**Then one walk, on Oxide and Carbon, of everything still owed (D331):** §2.7; §11's rows; §12.9; §13's and
|
||||
§14's rows; the in-game rows
|
||||
@@ -1102,7 +1103,7 @@ The org lead answered §14.3's Q26–Q32 on 2026-10-14:
|
||||
| **D380** | **A guarded crate left standing is noted in the run log when it is placed, not when the run ends:** the *Place a guarded crate* step's success line says the crate is kept when the run ends and how it ends (org lead, 2026-10-15). Core gives a module no hook at a run's end for a step that is kept, so D373's note at the end would need new core work. | A run-end hook in core now (a MODULE_API minor, with the Module-uo proof), or filed for later. | 14.3.5, 14.3.19 |
|
||||
| **D381** | **Server Rewards is taken off the plan** (org lead, 2026-10-16: *"I do not want it"*). Stage 8 is not built. Gone with it: `integrations.serverRewards`, `points.pay` / `balances` / `adjust` and the sidecar's three routes, the tally's `points`, the step `rust.points.pay` and its budget, the `rust_player_points` table, staff add and take, the app's RP balance, and the *Hoarder* title and its column. It amends D350 (five plugins, not six), D369 (its wipe half now covers ZLevels only), D375 and D377 (no *Hoarder*). Nothing had been built. §14.2.1's test findings stay as a record. | Building §14.3.7 as planned. | 14, 14.3.7, 14.3.11 |
|
||||
|
||||
Console commands as event steps and rewards, added on 2026-10-16, were decided as D382–D384; they are tabled with their section, in §16.7.
|
||||
Console commands as event steps and rewards, added on 2026-10-16, were decided as D382–D384, and D385 during the build; they are tabled with their section, in §16.7.
|
||||
|
||||
## 11. First-class optional plugins (D199–D202)
|
||||
|
||||
@@ -3351,7 +3352,8 @@ A reward that runs the admin's commands once for each recipient.
|
||||
goes out once after the end walk (D332). This is how every item since §2 has added to it.
|
||||
- **Request:** `{ key, commands: [..], recipients?: [{ steamId, name }] }`. With no `recipients` the commands
|
||||
run once (§16.2). With `recipients` they run once per online recipient, after the placeholders are filled
|
||||
(§16.3).
|
||||
(§16.3). **D385 adds `teardown` to a run, which the bridge keeps with the key, and `{ key, teardownOf }`,
|
||||
which runs the kept teardown** (§16.10).
|
||||
- **Main thread, spread over frames.** A full reward is at most 100 × 10 commands, so the bridge runs a bounded
|
||||
number per frame rather than all in one, and answers inside the step's 15 s budget (`BUDGET_MS`).
|
||||
- **At most once, by the key.** A command cannot be asked whether it already ran. So the bridge records the
|
||||
@@ -3403,6 +3405,7 @@ Answered by the org lead on 2026-10-16.
|
||||
| **D382** | **An event can run console commands an admin types**: a *Run console commands* step, with optional commands at teardown, and a *Reward by console command* reward run once per recipient. Both are module actions in Module-Rust within the event system as it stands. They are one item, planned here and built as one stage. | Writing a first-class integration for every plugin used in events; a game-agnostic command action in core (ADMIN_CONTROLS §8a admits only declared actions). | 16.2, 16.3 |
|
||||
| **D383** | **A command reward skips recipients who are offline** and names them in the step's detail. It does not hold the commands until they next join, *"for now"*. | A queue in the bridge that runs held commands when the player connects and survives a restart. | 16.3 |
|
||||
| **D384** | **No allowlist for these commands**: the admin types them into a free text box. What bounds them is core's: the step is off until an admin switches it on, only an admin may author it, the switchboard's caps, and the "I am sure" toggle. | An allowlist of command prefixes in the bridge's config, empty by default; an allowlist on the site. | 16.2, 16.4 |
|
||||
| **D385** | **The bridge keeps a step's teardown with its key** (org lead, 2026-10-16, during the build). A run sends its `teardown` with its commands, and the bridge stores it without running it. A revert that has only the key asks every enabled server to run the teardown it kept under that key, at most once, and only where something may have run. That is the case of a step that failed after a first command ran, or whose answer was lost: core records no ledger row for either, so the plan's ledger copy never reaches them. The ledger row keeps its own copy for every step that succeeded. | Perform runs the teardown itself when a step fails part-way, and a lost answer leaves the row visible for an operator; or no teardown for a failed step, left to the operator. | 16.4, 16.10 |
|
||||
|
||||
### 16.8 Where the work lands, and in what order
|
||||
|
||||
@@ -3432,4 +3435,62 @@ Economics' `deposit` meanwhile):
|
||||
see the online one rewarded, the offline one named as skipped, and a player whose name has spaces and a
|
||||
quote get it right;
|
||||
- retry a step after its answer is lost (stop the sidecar mid-step) and see nothing run twice;
|
||||
- (D385) give a step a teardown, make its first command work and its second misspell, and see the run abort
|
||||
and the teardown run once, from the bridge's copy;
|
||||
- **on Carbon**, see a plugin's command run, the confirmation §14.3.14 point 7 asked for.
|
||||
|
||||
### 16.10 Built (2026-10-16)
|
||||
|
||||
Built as §16.8's one stage the day it was planned. The branches are `feat/command-steps` in Rust-Plugins,
|
||||
Rust-Link and Module-Rust, into `edge`, with this record on `docs/command-steps-built`. The specification is
|
||||
[PROTOCOL.md](../../rust-link/PROTOCOL.md) §20.11. The walk rows (§16.9) join the end walk (D331).
|
||||
|
||||
**Spiked first on both rigs** (Rust 25902425, Oxide 2.0.7830, Carbon 2.0.262), from a timer, the context the
|
||||
console probe measures:
|
||||
|
||||
1. **`ConsoleSystem.Run` returns `null` both for a command the server does not know and for one that replies
|
||||
nothing** (`rg.probe`), so the plan's "the game answers *Command '…' not found*" is not in the return value.
|
||||
**The game logs that line synchronously inside the call**, as `Command '<the whole line>' not found`, the
|
||||
same on both frameworks. The bridge listens to Unity's log while each command runs. That line is
|
||||
`unknown-command`, and anything else heard is the reply when `Run` returns nothing (`oxide.version` replies
|
||||
only by logging).
|
||||
2. **`QuoteSafe()` (the game's own quoting) is available to a plugin on both**, and `"na\"me; status"` arrives
|
||||
as one argument, `na"me; status`. **`;` does not separate console commands**: `x; status` is one command
|
||||
with two arguments. So `{name}` is filled quoted, and a name cannot run anything else.
|
||||
3. **Plugin commands run on Carbon** from that context (`consolePlugins=True` on the Carbon rig), so
|
||||
§14.3.14 point 7's confirmation now waits only for the end walk's real path through the reader thread.
|
||||
|
||||
**Then compiled on both rigs**, and driven through a throwaway plugin calling the bridge's handler (no sidecar).
|
||||
On both frameworks a repeat key ran nothing, a misspelled second command stopped as `unknown-command` after the
|
||||
first, offline recipients were skipped and named (a quote in a name intact), malformed requests were refused,
|
||||
and D385's teardown ran once for a run that had run something, and not at all for one that had run nothing or
|
||||
was unknown. Both rigs were put back on the protocol-13 bridge.
|
||||
|
||||
**D385 was asked during the build.** Core records nothing from a failed step and reverts its placeholder with
|
||||
only the key (EVENTS.md §D), so the ledger copy the plan relied on never reaches a step that failed part-way.
|
||||
§16.7 has the decision.
|
||||
|
||||
**Settled in code** (each can be overruled):
|
||||
|
||||
1. **A retry while the first run is still going joins it.** The sidecar's reply timeout (10 s) is shorter than
|
||||
the step's budget (15 s), so a full reward can be retried while it runs. The retry is answered when the run
|
||||
ends, with the same answer.
|
||||
2. **A run that a restart or a reload cut off is `interrupted`**: permanent, nothing run again, and its teardown
|
||||
(D385) still runs.
|
||||
3. **Per frame:** whole recipients, until 30 commands or 8 ms. A run without recipients (at most 10) is one
|
||||
frame.
|
||||
4. **Commands run not quiet**, so the server console shows each one and its answer as if typed.
|
||||
5. **The answer keeps the first 20 replies** (each trimmed to 200 characters) and the first 50 skipped names
|
||||
with a count. The key file keeps at most 500 keys, oldest forgotten first, besides the plan's seven days.
|
||||
6. **A teardown takes no placeholders, and a reward takes no teardown** (refused `malformed`).
|
||||
7. **The name filled in is the player's in-game name** as the server has it at that moment, not the site's copy.
|
||||
The site's name is used only to name someone skipped.
|
||||
8. **`{steamid}` and `{name}` ignore case.** Any other `{…}` is left as typed, since a command may need braces.
|
||||
9. **Nobody qualifying sends nothing** (the step says *"nobody qualified, so no command ran"*).
|
||||
10. **`multiple` drops duplicates** (MODULE_API 1.14.0), so a command listed twice runs once. A step that wants
|
||||
`airdrop` twice uses two steps, or *Call a world event*.
|
||||
11. **Permanent failures:** `malformed`, `unknown-command`, `interrupted`, `failed`, `events-disabled`. The
|
||||
error says how many commands ran before it. A game that is down or a world still loading retries on core's
|
||||
ordinary delay.
|
||||
12. **A teardown's `unknown-command` fails the revert** and leaves the row visible: core's cleanup retries
|
||||
replay the key's first answer, so nothing runs twice.
|
||||
|
||||
Reference in New Issue
Block a user