docs(rust): stage 3 built — TruePVE in the zone step (PROTOCOL §20.6, PLAN_REDESIGNS §14.3.16)

- rust-link/PROTOCOL.md §20.6: hello's integrations.truePve, world.zone's
  truePve (exactly one of exclude and ruleset, all or nothing, the
  refusals), the unmapping on every erase path with truepve.json for
  while TruePVE is away, rg.world's two fields, and the website's two
  params. The §15 command table points at it.
- modules/rust/PLAN_REDESIGNS.md §14.3.16: the stage-3 record, ten points
  settled in code (all overrulable), TruePVE's one-second save, the tests
  and the rig compile. Pointers from §9's summary and §14.3.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-15 05:47:27 -05:00
parent bf2524aa6c
commit 65c57cec36
2 changed files with 101 additions and 2 deletions

View File

@@ -930,7 +930,7 @@ pulls) is research, not a walk, so it still comes first:
answered before code: **written on 2026-10-14 as §14.3**, from D361–D369, and answered as D370–D376. Then the
build, in §14.3.11's nine stages (two of them core), §13 first. **Stage 1, §13, was built on 2026-10-15
(§14.3.14)**, with D378 and D379. **Stage 2, core's `retryAfterMs` (MODULE_API 1.15.0), was built on
2026-10-15 (§14.3.15).**
2026-10-15 (§14.3.15).** **Stage 3, TruePVE in the zone step, was built on 2026-10-15 (§14.3.16).**
**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
@@ -2501,6 +2501,8 @@ helicopter from a run, then cancel the run and see both stay; a Guarded Crate cr
#### 14.3.2 TruePVE in the zone step (D362, D368)
> **Built on 2026-10-15** (§14.3.16), specified in PROTOCOL.md §20.6.
**Hello.** `integrations.truePve`: `{ loaded, version }`.
**The wire.** `world.zone` gains an optional **`truePve`**: `{ "exclude": true }` or `{ "ruleset": "pvp-arena" }`
@@ -2933,6 +2935,47 @@ machine's installed `modules/`; client 422/422 and the build.
**No walk rows of its own.** Stage 5's Dangerous Treasures rows exercise it: a step answering *"not ready"*
shows *"retrying at …"* and runs then.
#### 14.3.16 Stage 3, built: TruePVE in the zone step (2026-10-15)
Built in Rust-Plugins and Module-Rust as §14.3.2 planned it, specified in
[PROTOCOL.md](../../rust-link/PROTOCOL.md) §20.6. **No Rust-Link change**: the sidecar forwards `world.zone`
whole. `PROTOCOL_VERSION` stays 14. Builds: Rust 25902425, Oxide 2.0.7830, Carbon 2.0.262, TruePVE 2.4.6 on both
rigs.
**Settled in the code, and overrulable:**
1. **A ruleset name is trimmed and 1–64 characters**, checked by the site and the plugin alike; past that it
is passed as written, because TruePVE compares names case-sensitively (`r.name == ruleset` in 2.4.6).
2. **A server whose hello has not said whether it has TruePVE is left to the plugin** (a plugin before
protocol 14, or never reached), as a dome is, and the plugin answers `truepve-missing`. Only a hello that
says `loaded: false` is refused at verify.
3. **`exclude` refused by TruePVE answers `refused`, not `truepve-ruleset`.** It happens only when TruePVE has
not read its config or data yet; the zone is erased all the same.
4. **The mapping comes after the dome**, so a refusal erases both, as a failed dome erases its zone.
5. **Re-creation maps nothing again.** TruePVE keeps the mapping in its own data file, keyed by the zone id,
which re-creation keeps.
6. **Two erase paths beyond the plan's three are covered:** a zone `world.owned` finds ZoneManager no longer
holds, and a new wipe dropping the old map's entries. TruePVE's table outlives a wipe.
7. **Leftovers are also flushed at the bridge's own load**, not only at `OnPluginLoaded(TruePVE)`, so a bridge
reloaded after TruePVE came back does not wait for TruePVE's next reload. `truepve.json` is deleted when empty.
8. **Hello is sent again when TruePVE loads or unloads**, so the site's verify reads the current answer.
9. **`truepve-missing` and `truepve-ruleset` are permanent failures**, as `no-zone` is.
10. **Server settings' plugin line names TruePVE**: *"TruePVE 2.4.6 is loaded — a zone step may turn off PvP
protection or name a ruleset."*
**One thing TruePVE does that we cannot change:** it saves its data file one second after a change, on its
own timer. A restart inside that second loses the change. For a removal that leaves a mapping for an `rg-…` id
no zone will have again, which changes nothing in game; D362's cleanup is otherwise complete.
**Tests.** Module-Rust: five new in `test/zones.test.js` (exclude, `"true"` and a trimmed ruleset on the wire;
unset, off and blank send nothing; both, a long name and no TruePVE refused for good at verify and perform; a
hello that has not said is left to the plugin; `truepve-ruleset` and `truepve-missing` fail for good with the
plugin's words). Full suites: server 603/603 and every check (imports, bundle, swagger, engagement); client
84/84, the build and externals. The plugin compiled and loaded on both rigs, and `rg.world` read
`truePve=True truePveLeftover=0` on each; both rigs were put back on the protocol-13 bridge after.
**Walk rows** are §14.3.2's, at the end walk (D331, D359).
### 14.4 Questions for the org lead
**Answered on 2026-10-14:** Q17 as proposed, out (D358). **Q18 against the proposal: the end walk waits for

View File

@@ -1436,7 +1436,7 @@ five routes.
| Command | Answers | |
|---|---|---|
| `world.monuments` | `world.monuments` | This map's monuments in one stable order (grouped by prefab short name, then by position). Each has `value` (`kind`, or `kind#n` when the kind repeats), `kind`, `instance`, `of`, `label` (the game's display phrase), `x`, `z` and `grid`. Also `worldSize`, the placeable `prefabs` (`key`, `kind`, `label`), `eventsEnabled`, `maxCrates`, `maxNpcs` and `zoneManager` |
| `world.zone` | `world.ok` or `world.error` | Opens a ZoneManager temporary zone owned by the bridge. Needs `runId`, `key`, a location, `radius` (5–150 m) and `holdMs` (1 minute to 7 days); `name` is optional. Protocol 13 adds `flags`, `settings`, `enterMessage`, `leaveMessage`, `delivery`, `format` and `dome` (§19.11) |
| `world.zone` | `world.ok` or `world.error` | Opens a ZoneManager temporary zone owned by the bridge. Needs `runId`, `key`, a location, `radius` (5–150 m) and `holdMs` (1 minute to 7 days); `name` is optional. Protocol 13 adds `flags`, `settings`, `enterMessage`, `leaveMessage`, `delivery`, `format` and `dome` (§19.11); protocol 14 adds `truePve` (§20.6) |
| `world.place` | `world.ok` or `world.error` | Places `count` of one allowlisted `prefab` at a location, scattered within `spread` m (0–50, 10 by default for a group). All or nothing: if the game refuses one, the ones already made are killed. Protocol 13 adds `profile`, a RunicNPC profile in place of a prefab (§19.12), and for a profile `escort`, `ally` and `tether` (§19.13) |
| `world.revert` | `world.ok` | Gives back what a run owns: the named `ids`, or else everything under `key`, or else everything the run owns. The answer lists `removed`, `gone` and `refused` |
| `world.owned` | `world.owned` | What the world still holds of what events made, **looked for** by net id or zone id, narrowed by `runId`. Anything gone is pruned from the registry as the walk passes it |
@@ -3019,3 +3019,59 @@ is every website command's path. On both rigs it reads `true`. Hello is sent aga
- **The tally's two counts** in `rust_player_wipe_stats.crates_hacked` and `.drops_looted`; title categories
`crateshacked` (*Safecracker*) and `dropslooted` (*Scavenger*); leaderboard columns *Crates hacked* and *Drops
looted*, sortable (`sort=cratesHacked`, `sort=dropsLooted`).
### 20.6 TruePVE in a zone — `world.zone`'s `truePve` (§14.3.2, D362, D368)
nivex's **TruePVE** (2.4.6, uMod), optional like Economics (D199) and not in `overlay.toml`. A zone an event
opens may ask TruePVE to leave it alone, or to use one of the operator's rulesets inside it. The design is
[`PLAN_REDESIGNS.md`](../modules/rust/PLAN_REDESIGNS.md) §14.3.2, and what §14.2's test found, which shapes it,
is §14.2 there. None of TruePVE's hooks is used.
**Hello and status.** `integrations` gains `truePve`:
```json
"truePve": { "loaded": true, "version": "2.4.6" }
```
Hello is sent again when TruePVE loads or unloads.
**`world.zone` gains an optional `truePve`** (the rest of the zone is §15 and §19.11):
```json
{"cmd":"world.zone","reqId":"r-4","runId":"13","key":"9c1e…","monument":"airfield_1","radius":40,
"holdMs":1800000,"truePve":{"exclude":true}}
{"cmd":"world.zone","reqId":"r-5","runId":"13","key":"0b7d…","monument":"launch_site_1","radius":60,
"holdMs":1800000,"truePve":{"ruleset":"pvp-arena"}}
```
- **Exactly one of `exclude` and `ruleset`.** `exclude` is `true` or left out; `ruleset` is 1–64 characters
after trimming, passed as written, because TruePVE matches its names case-sensitively. Both, neither, a
non-object or a blank name is **`malformed`**.
- **TruePVE not loaded** is **`truepve-missing`**, before anything is made.
- **All or nothing.** The bridge makes the zone, and its dome when asked, then calls
**`AddOrUpdateMapping(zoneId, "exclude" | ruleset)`**. TruePVE answers false for a ruleset it does not have,
and nothing else lists the names, so the call is the check (D368). A false erases the dome and the zone
just made and answers **`truepve-ruleset`** with the name, or **`refused`** for `exclude` (TruePVE not ready).
- The registry entry keeps the mapping it was given (`TruePve`), so a mapping is only ever removed for a zone
this plugin mapped. **Re-creating a zone** (a restart, a hot reload, a ZoneManager reload, §19.11) maps
nothing again: TruePVE keeps its table in its own data file, and the zone keeps its id.
**The unmapping lives with the zone (D362).** TruePVE prunes a mapping whose zone is gone only when the zone
id is a number, and ours are `rg-…`. So every path that erases one of our zones calls **`RemoveMapping`**
first: its deadline (checked every second, with the site down too, §15.3), `world.revert`, a zone that
`world.owned` finds ZoneManager no longer holds, and a new wipe dropping the old map's entries. When TruePVE is not loaded at
that moment, the id goes into **`data/RunicGateway/truepve.json`**, and the bridge removes each one at
`OnPluginLoaded(TruePVE)` (TruePVE has read its table in `Init` by then) and at its own load. The file is
deleted when it is empty.
**Status.** `rg.world` prints `truePve=` (loaded) and `truePveLeftover=` (ids waiting in `truepve.json`).
**The sidecar** forwards `world.zone` whole, as before; nothing in it changed.
**The website (Module-Rust).** `rust.zone.open` gains **`noPvpProtection`** (a boolean, *"No PvP protection in
this zone"*) and **`pvpRuleset`** (a string, *"or this TruePVE ruleset"*). Setting both is refused, as is a
name over 64 characters, and either one is refused where the server's last hello said TruePVE is not loaded
(*"TruePVE is not installed on this server"*); all three at verify too. A server whose hello has not said
(a plugin before protocol 14, or never reached) is left to the plugin. `truepve-missing` and
`truepve-ruleset` fail the step for good, with the plugin's words. Server settings' plugin line says whether
TruePVE is loaded.