Commit Graph

157 Commits

Author SHA1 Message Date
68a8d637f5 chore(engagement): regenerate the manifest for coreApi ^1.21.0
All checks were successful
PR Checks / client-build (pull_request) Successful in 1m7s
PR Checks / server-tests (pull_request) Successful in 1m24s
PR Checks / frozen-manifest (pull_request) Successful in 2m25s
#72 raised coreApi to ^1.21.0 without regenerating
engagement-triggers.json, which embeds it, so check:engagement has
failed since. That went unseen on #72 (its server-tests job died on a
full runner disk before the check) and surfaced on the cutover (#73).
Only the coreApi line changes; no trigger, stream, audience or rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-30 16:55:00 -05:00
0c29dbf6eb Merge pull request 'feat(safety): report, block and hide chat lines (MODULE_API 1.21.0)' (#72) from feature/user-safety into edge
Some checks failed
PR Checks / client-build (pull_request) Successful in 49s
PR Checks / frozen-manifest (pull_request) Successful in 1m17s
PR Checks / server-tests (pull_request) Failing after 58s
Reviewed-on: #72
2026-10-30 14:20:39 +00:00
dd9b8b2711 feat(safety): report, block and hide chat lines (MODULE_API 1.21.0)
Some checks failed
PR Checks / client-build (pull_request) Successful in 51s
PR Checks / frozen-manifest (pull_request) Successful in 53s
PR Checks / server-tests (pull_request) Failing after -17s
USER_SAFETY.md step 3, the module half of report, block and hide.

- server/safety.js registers the rust.chat report target (snapshot for one
  reader, null when they could not have seen the line; staff's hide and
  unhide) and the steam game identity (ownersOf from rust_account_links).
- The events feed filters chat per reader, in the query: lines from a
  blocked account's Steam ids, the reader's unlinked Steam-ID blocks and the
  lines they hid. Signed-in readers get canBlock on each chat line (false for
  their own and for staff-linked players). Lines staff hid for everyone are
  left out for everyone but staff, who get them with hidden: true.
- rust_events gains hidden_at and hidden_by (ALTER ... IF NOT EXISTS).
- POST /admin/rust/chat/:id/hide and /unhide (admin, moderator), logged.
- The feed's chat lines get a menu: Report, Hide for me, Block player,
  and for staff Hide for everyone / Show to everyone again.
- coreApi ^1.21.0; ci/core-ref.json pinned to the website#233 merge;
  routes.manifest.json and swagger-fragment.json regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-30 09:04:08 -05:00
1fb685fa0f Merge pull request 'chore: remove a stray empty file committed by #70' (#71) from fix/stray-file into edge
Reviewed-on: #71
2026-10-30 09:30:40 +00:00
bd13f197c5 chore: remove a stray empty file committed by #70
All checks were successful
PR Checks / client-build (pull_request) Successful in 51s
PR Checks / frozen-manifest (pull_request) Successful in 1m19s
PR Checks / server-tests (pull_request) Successful in 35s
`Promise.reject(dup)` is a zero-byte file a tool hook wrote into the working
tree; #70 committed it by accident. Nothing reads it. Found in the account
deletion walk (docs/website/ACCOUNT_DELETION.md step 6, W1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-30 03:56:42 -05:00
e30c7d591d Merge pull request 'feat(links): unlink every Steam id before an account is deleted (MODULE_API 1.20.0)' (#70) from feature/account-deletion-hook into edge
Reviewed-on: #70
2026-10-30 04:48:54 +00:00
b5573d9ae3 feat(links): unlink every Steam id before an account is deleted (MODULE_API 1.20.0)
All checks were successful
PR Checks / server-tests (pull_request) Successful in 1m1s
PR Checks / frozen-manifest (pull_request) Successful in 1m28s
PR Checks / client-build (pull_request) Successful in 43s
ACCOUNT_DELETION.md §4.4 (AD10). api.onUserDeleting calls links.unlinkForDeletion,
which runs the player's own unlinkOwned per link, logs rust.account.unlink with
reason 'account deleted', and marks every server's permission sync dirty so the
withdrawn grants reach the game on the next tick. coreApi ^1.20.0; core-ref pinned
to website#232's merge (7bd93b8); engagement manifest regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-29 20:38:30 -05:00
ec90d2d5ae Merge pull request 'fix(demo): lock removing a Steam link on the demo (DM27)' (#67) from fix/demo-lock-steam-unlink into edge
All checks were successful
PR Checks / server-tests (pull_request) Successful in 42s
PR Checks / client-build (pull_request) Successful in 58s
PR Checks / frozen-manifest (pull_request) Successful in 1m7s
Reviewed-on: #67
2026-10-28 09:47:44 +00:00
fb7511d700 fix(demo): lock removing a Steam link on the demo (DM27)
All checks were successful
PR Checks / server-tests (pull_request) Successful in 54s
PR Checks / client-build (pull_request) Successful in 1m5s
PR Checks / frozen-manifest (pull_request) Successful in 1m36s
The step-5 walk found demo-player could remove its stand-in Steam link from
its Rust page, and staff could remove it from Admin -> Users. That link is
what the player tour's Rust pages, rewards and grants hang on.

- module.json demoLocks gains DELETE /player/rust/links/:steamId.
- The staff route, DELETE /admin/users/:id/rust/links/:steamId, serves under
  core's users mount, which a module's demoLocks may not name, so its handler
  refuses with DEMO_LOCKED behind ctx.demoMode before the link is touched.

Off the demo both behave as before. Checked on a real core with the demo
seed: both answer 403 DEMO_LOCKED and the link stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-28 04:44:28 -05:00
5c9cefdbc2 Merge pull request 'fix(demo): seed NPC profiles, factions and chat styles (DM26)' (#65) from feat/demo-seed-npcs-chat into edge
All checks were successful
PR Checks / server-tests (pull_request) Successful in 38s
PR Checks / client-build (pull_request) Successful in 55s
PR Checks / frozen-manifest (pull_request) Successful in 59s
Reviewed-on: #65
2026-10-28 01:22:44 +00:00
1f4ad25edb fix(demo): seed NPC profiles, factions and chat styles (DM26)
All checks were successful
PR Checks / server-tests (pull_request) Successful in 55s
PR Checks / client-build (pull_request) Successful in 1m7s
PR Checks / frozen-manifest (pull_request) Successful in 1m36s
The demo's first restored wipes brought the default set's groups and
permissions back, but not its NPCs or chat titles. The restored rig's
RunicNPC says it is already managed (by the site before this one), so the
fresh site adopts nothing (D244) and its first push empties the profiles;
the placements then wait on missing profiles. The import never adopts a
group's chat style either.

onDemoSeed now also takes:
- npcs.factions: the faction table, through the NPC model's setFactions;
- npcs.profiles: each profile through the model's create/update, so it is
  checked exactly as the admin page checks it (an existing one is updated);
- chat: a BetterChat style per server and group, the defaults filled in. A
  group the rig's import has not brought in yet is created for that server,
  and the import then adopts the rig's title, rank and permissions into it.

The section's new parts are checked before anything is written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-27 20:15:32 -05:00
228e178475 Merge pull request 'release: the public demo's module-side locks and seed hook (v0.6.0, MODULE_API 1.19.0)' (#64) from edge into main
All checks were successful
Release / release (push) Successful in 45s
Reviewed-on: #64
v0.6.0
2026-10-27 17:32:01 +00:00
0cdb046d30 Merge pull request 'chore(ci): pin core-ref to website#224's merge on main' (#63) from chore/core-ref-224-merge into edge
All checks were successful
PR Checks / server-tests (pull_request) Successful in 41s
PR Checks / client-build (pull_request) Successful in 47s
PR Checks / frozen-manifest (pull_request) Successful in 58s
Reviewed-on: #63
2026-10-26 11:03:06 +00:00
791f13235e chore(ci): pin core-ref to website#224's merge on main
All checks were successful
PR Checks / client-build (pull_request) Successful in 1m2s
PR Checks / server-tests (pull_request) Successful in 1m8s
PR Checks / frozen-manifest (pull_request) Successful in 1m35s
website#224 (MODULE_API 1.19.0, demoRefuses) merged as 69998ec on main.
The merge tree equals the branch head the pin held (cee4ab8), so
routes.manifest.json does not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-26 05:53:41 -05:00
c61f9f29ec Merge pull request 'feat(demo): the public demo's module-side locks and seed hook' (#62) from feat/demo-mode into edge
Reviewed-on: #62
2026-10-26 10:52:25 +00:00
7a0d0842ba feat(demo): the public demo's module-side locks and seed hook
All checks were successful
PR Checks / client-build (pull_request) Successful in 54s
PR Checks / server-tests (pull_request) Successful in 1m0s
PR Checks / frozen-manifest (pull_request) Successful in 1m19s
website/DEMO_MODE.md §3.2, §3.4, §3.5, §7.3 and §7.5 (step 2 of §10).
Nothing changes off the demo; everything below sits behind ctx.demoMode.

- demoLocks in module.json: PUT and DELETE /admin/rust/servers/:id.
- The console-command deny list (DM11): quit, restart, oxide.unload,
  oxide.reload, rcon.*, fps.limit and server.tickrate, by first word,
  with global. stripped and o. read as oxide. Refused at save through
  core's demoRefuses (MODULE_API 1.19.0, DM18) and again at run, with
  retry: false, before the rig is asked. Teardown commands too.
- The config editor (DM14): the bridge's files are left out of the
  list and refused for reading, writing and in the write history, by
  name (canonicalised) and by the catalogue's self. Other plugins'
  credential fields are redacted in the text and the form and made
  read-only; raw-JSON saves are refused; a file that does not parse is
  withheld. The admin server list leaves out the sidecar URL.
- onDemoSeed (DM15): upserts the rig's server row with an encrypted
  token and demo-player's stand-in Steam link.
- The release's install manifest carries protocol, read from
  PROTOCOL_VERSION, for the wipe's bundle match (DM12).

coreApi is ^1.19.0; ci/core-ref.json pins website#224's head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-26 03:40:30 -05:00
bc529962b4 Merge pull request 'release: weapon names and the admin copy fixes (v0.5.1)' (#61) from edge into main
All checks were successful
Release / release (push) Successful in -1m57s
Reviewed-on: #61
v0.5.1
2026-10-23 07:07:21 +00:00
c4729315cd Merge pull request 'fix(feed): print weapons by name, not "ak47u entity"' (#60) from fix/weapon-names into edge
All checks were successful
PR Checks / client-build (pull_request) Successful in 50s
PR Checks / frozen-manifest (pull_request) Successful in 1m27s
PR Checks / server-tests (pull_request) Successful in 7m25s
Reviewed-on: #60
2026-10-23 06:26:39 +00:00
55a9ea4649 fix(feed): print weapons by name, not "ak47u entity"
All checks were successful
PR Checks / client-build (pull_request) Successful in 33s
PR Checks / server-tests (pull_request) Successful in 43s
PR Checks / frozen-manifest (pull_request) Successful in 1m5s
The bridge names a kill's weapon by the held entity's short prefab name
(ak47u.entity), and the feed printed it with the dots turned to spaces:
"with ak47u entity". Every event read now gives the frame a weaponName
(server/model/titles/weaponNames.js): the game's own English name for the
53 ranged weapons (guns, bows, crossbows, launchers, flamethrowers), read
off the Oxide rig's item list on Rust 26139947, and for anything else the
prefab name as words with its .entity/.weapon ending dropped.

The site prints weaponName and falls back to the same stripping for an
older server. The prefab name stays in the frame: the title lists count by
it. Added at read, so stored rows are renamed too. No protocol change; the
events route's Swagger description names the new field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-23 01:22:37 -05:00
2e80a21597 Merge pull request 'fix(admin): no decision numbers in admin copy, and "1 player holds one"' (#59) from fix/admin-copy into edge
Reviewed-on: #59
2026-10-22 20:32:52 +00:00
3741c954f5 fix(admin): no decision numbers in admin copy, and "1 player holds one"
All checks were successful
PR Checks / client-build (pull_request) Successful in 34s
PR Checks / frozen-manifest (pull_request) Successful in 1m3s
PR Checks / server-tests (pull_request) Successful in 7m12s
Twenty-four strings an administrator reads carried an internal decision
number - "(D189)", "(D198)", "(D257, D270)" and the like: the permission
screen's group Servers tab and a chip tooltip, the event editor's step
field and budget descriptions, two option sources, a command reward's
skipped note, and five NPC profile validation errors. A D-number means
something to the plan, never to an operator. Each is removed, and the
sentence around it left as it was. The developer-facing swagger
descriptions and code comments keep theirs.

The servers page's chat-title line read "Last pushed: 1 player hold
one." It now says "holds" for one.

Two tests pinned the old wording and now assert the text instead.

Found while writing the runicgateway.com Rust docs (its PLAN.md §16,
phase 15).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-22 15:28:35 -05:00
3fac860949 Merge pull request 'chore(release): cut edge over to main — protocol 14 and Steam sign-in (MODULE_API 1.17.0)' (#58) from edge into main
All checks were successful
Release / release (push) Successful in 36s
Reviewed-on: #58
v0.5.0
2026-10-22 11:16:11 +00:00
42bd6db6ad Merge pull request 'ci(rust): pin core to main at the cutover (website#220)' (#57) from chore/pin-core-main into edge
All checks were successful
PR Checks / server-tests (pull_request) Successful in 35s
PR Checks / frozen-manifest (pull_request) Successful in 1m9s
PR Checks / client-build (pull_request) Successful in 7m9s
Reviewed-on: #57
2026-10-22 11:13:51 +00:00
3453bc1867 ci(rust): pin core to main at the cutover (website#220)
All checks were successful
PR Checks / client-build (pull_request) Successful in 31s
PR Checks / frozen-manifest (pull_request) Successful in 59s
PR Checks / server-tests (pull_request) Successful in 7m15s
website#220 cut website edge over to main as 6890a74. The pin pointed at
9a1654f, the sha website#218 merged into edge as, which its own note said
moves to main when the cutover lands. The new tree adds the last fixes'
core half (website#219, no MODULE_API bump), whose route changes are only
core's own event routes, so routes.manifest.json does not change. The
frozen-manifest job, replayed locally at this ref, passes (89 routes, all
documented).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-22 05:45:25 -05:00
72726838b5 Merge pull request 'fix(rust): a zone resource carries its deadline as until (W1)' (#56) from fix/last-fixes-zone-until into edge
Reviewed-on: #56
2026-10-22 06:26:56 +00:00
9c35906d0e fix(rust): a zone resource carries its deadline as until (W1)
All checks were successful
PR Checks / client-build (pull_request) Successful in 31s
PR Checks / frozen-manifest (pull_request) Successful in 1m1s
PR Checks / server-tests (pull_request) Successful in 7m20s
Stage 4 of docs/modules/rust/PLAN_LAST_FIXES.md, the module's half of W1.
A placed zone now reports `until`, reckoned from the answer as now plus
holdMs, so it lands a round trip after the game's own deadline and never
before it. Core's reconcile then files a zone gone past that deadline as
expired, where a reconnect used to log resource.orphaned five seconds
before the game's world.expired arrived. Crates and NPCs send no
holdMs, so they carry no until.

No core pin change: `until` has been in the resource contract all along,
and a core without the reconcile half only shows it on the console.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-22 00:38:49 -05:00
7304d68d0a Merge pull request 'fix(rust): the last fixes' small ones (W3 W6 W7/W11 W8 W10 W13-W18)' (#55) from fix/last-fixes-small into edge
Reviewed-on: #55
2026-10-21 18:45:37 +00:00
3aa142bf06 fix(rust): the last fixes' small ones (W3 W6 W7/W11 W8 W10 W13-W18)
All checks were successful
PR Checks / client-build (pull_request) Successful in 24s
PR Checks / server-tests (pull_request) Successful in 32s
PR Checks / frozen-manifest (pull_request) Successful in 44s
Stage 2 of PLAN_LAST_FIXES (docs#366).

- W7/W11: an "is it loaded" refusal is confirmed live before it is given.
  New liveStatus.js asks the sidecar once (boot.refreshOne, as a poll tick
  would), at most once per server per 5 s and waiting at most 3 s, then
  reads the stored status again. Used by Economics (step and staff page),
  Backpacks, Dangerous Treasures, Guarded Crate, RaidableBases, ZoneDomes,
  TruePVE and RunicNPC.
- W3: a world call answered `already-out` (the bridge half comes in stage
  3) succeeds as called 0, saying a Travelling Vendor is already out.
- W6: "A locked crate dropped by a Chinook is being hacked."
- W8: a RaidableBases profile's audit row names RaidableBases, not "@data".
- W10: the backpack sizes picker lists each size once, naming its servers.
- W13: a RaidableBases name both servers describe differently shows each
  server's own description.
- W14: each RaidableBases note after the first starts its own sentence.
- W15: a staff deposit refused at Economics' limit answers 409.
- W16: a payment's failedNote explains only the reasons that happened.
- W17: the sync state counts player grants that did not land
  (waitingToLand), and the Permissions page says "in sync · 1 waits for
  their player to join" instead of plain "in sync".
- W18: Guarded Crate's kept note drops the "30 minutes" it could not know.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-21 07:42:24 -05:00
d69c2108c6 Merge pull request 'fix(rust): send reward notices, and keep a downed line's credit rule (W21, W4)' (#54) from fix/last-fixes-bugs into edge
Reviewed-on: #54
2026-10-21 12:00:33 +00:00
8aff9b33a6 fix(rust): send reward notices, and keep a downed line's credit rule (W21, W4)
All checks were successful
PR Checks / client-build (pull_request) Successful in 21s
PR Checks / frozen-manifest (pull_request) Successful in 48s
PR Checks / server-tests (pull_request) Successful in 7m16s
W21: the permission push named its fields one by one and left out
`notices`, so no kit reward, lend or give ever told its player
anything (D333). The body is now built by `pushBody`, which carries
every field the payload has; a test fails if a payload field is
dropped again.

W4: a downed patrol helicopter, Chinook or Bradley is stored with the
credit rule in force when it arrived, and the feed reads that stamp.
Before, the line re-credited past rows with the server's current rule
while the Rotorbane/Tankbreaker counts kept the old one. Rows stored
before this change keep today's reading.

PLAN_LAST_FIXES.md stage 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-21 06:16:32 -05:00
5decd5cc05 Merge pull request 'ci(rust): pin core to the sha website#218 merged as' (#53) from chore/core-ref-steam-merge into edge
Reviewed-on: #53
2026-10-21 05:38:58 +00:00
885485d153 ci(rust): pin core to the sha website#218 merged as
All checks were successful
PR Checks / client-build (pull_request) Successful in 26s
PR Checks / frozen-manifest (pull_request) Successful in 51s
PR Checks / server-tests (pull_request) Successful in 7m14s
#218 (Steam sign-in, MODULE_API 1.17.0) merged into website edge as
9a1654f. The pin pointed at the PR's branch head, 5e398d8, while it was
open. The two trees differ by one core test file, so routes.manifest.json
does not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-21 00:38:15 -05:00
47da3a2db8 Merge pull request 'feat(rust): a Steam account linked on the site is a Rust link (D392, D396)' (#52) from feat/steam-signin-link into edge
Reviewed-on: #52
2026-10-20 15:25:44 +00:00
8172454683 ci(rust): pin core to website feat/steam-signin (MODULE_API 1.17.0)
All checks were successful
PR Checks / server-tests (pull_request) Successful in 37s
PR Checks / client-build (pull_request) Successful in 21s
PR Checks / frozen-manifest (pull_request) Successful in 48s
coreApi is ^1.17.0, which no core on main offers yet, so the frozen-manifest
job is proved against the head of the open website PR. Moves to the sha it
merges as.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-19 20:28:25 -05:00
b89039142e feat(rust): a Steam account linked on the site is a Rust link (D392, D396)
Registers core's MODULE_API 1.17.0 identity hooks (coreApi ^1.17.0):
onIdentityLinking refuses a Steam id that is another website account's Rust
link (D396); onIdentityLinked writes the Rust link with the PRIMARY KEY as the
race guard, reconciles Teams and raises the linked notice, as /link does.
Unlinking Steam leaves the Rust link (D393); the Rust account page says so.

ci/core-ref.json still pins the 1.15.0 core and must move to the website
branch head carrying 1.17.0 before CI can pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-19 14:02:53 -05:00
f93ba86883 Merge pull request 'feat(rust): RaidableBases — feed, raids map layer, Warlord, Spawn a raid base, profiles (PLAN_REDESIGNS §11.4)' (#51) from feat/raidable-bases into edge
Reviewed-on: #51
2026-10-17 06:33:08 +00:00
481837e937 feat(rust): RaidableBases — feed, raids map layer, Warlord, Spawn a raid base, profiles (PLAN_REDESIGNS §11.4)
All checks were successful
PR Checks / server-tests (pull_request) Successful in 37s
PR Checks / client-build (pull_request) Successful in 24s
PR Checks / frozen-manifest (pull_request) Successful in 49s
PLAN_REDESIGNS §11.4 (D202-D208, D386-D391), protocol 14. Spec: docs
rust-link/PROTOCOL.md §20.12.

- raid.started, raid.completed, raid.purchased and raid.locked public,
  raid.ended staff's; raidableBases.js reads each row per viewer (raiders'
  and a buyer's names only for the presence audience, D376/D390; Steam ids,
  position and a run's key only for staff). Feed lines in the World filter.
- The step rust.raidbase.spawn, "Spawn a raid base" (ledgered, budget
  rust.raids): difficulty, profile and base from option sources listing each
  server's own names (D386), a spot as a world call's location with a height
  adjustment or an exact height, and PvP/NPCs/lock as on/off/blank. A base
  the raids helper made is a world resource, so eventWorld's revert and
  reconcile serve it and world.expired marks it expired; one it did not make
  records nothing and the run log says it despawns on its own timer. Refused
  at verify for a server that said it cannot; a dry run with a spot returns
  the spot check as detail.warnings (MODULE_API 1.16.0, D391). rb-not-ready
  retries in ten minutes.
- Warlord: raids_completed, title category raidscompleted, the leaderboard's
  Raid bases column (sort=raidsCompleted).
- The map's raids layer (D114), public by default with its own audience; the
  run's key is dropped before any viewer gets it.
- Server settings' line for RaidableBases; its profiles in Mod configuration
  under a virtual path (D205).
- Swagger fragment, bundle and README.

Tests: server 684/684 (raidableBases.test.js new, every name in it invented);
client 99/99, build and externals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-16 15:18:52 -05:00
49d9e42a23 Merge pull request 'feat(rust): Run console commands and Reward by console command (PLAN_REDESIGNS §16)' (#50) from feat/command-steps into edge
Reviewed-on: #50
2026-10-16 07:47:28 +00:00
5686d9fd17 feat(rust): Run console commands and Reward by console command (PLAN_REDESIGNS §16)
All checks were successful
PR Checks / client-build (pull_request) Successful in 23s
PR Checks / server-tests (pull_request) Successful in 29s
PR Checks / frozen-manifest (pull_request) Successful in 56s
Two event steps in server/eventCommands.js, on one new budget,
`rust.commands` (D382-D385):

- rust.command.run: up to 10 typed commands once on one server, with
  optional teardown commands. irreversible / ledger: the ledger row keeps
  the teardown as it was, and core reverts it when the run ends or is
  cancelled. Priced one unit per command, teardown included.
- rust.command.reward: the kit reward's recipient picker (tally modes and
  linked), by Steam id, so no website account is needed. The bridge fills
  {steamid} and {name}; offline recipients are skipped and named (D383).
  irreversible / none. Priced commands x people, the bound for a mode that
  is not a count.

Both take core's `multiple` string field as a free text box (no
allowlist, D384) and a required "I am sure" toggle. {steamid}/{name} in a
run step are refused. unknown-command, malformed, events-disabled,
interrupted are permanent; the error says how many ran before it.

D385: the run also hands its teardown to the bridge, which keeps it with
the key. A revert with only the key (the step failed, or its answer was
lost, so core recorded nothing) asks every enabled server to run what it
kept; a server the step never reached runs nothing.

sidecarClient.commandsRun -> POST /commands/run; ci/bundle.json lists the
new file; entry.test.js pins the new ids; 21 tests in
test/commandSteps.test.js.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-16 02:41:10 -05:00
619081ec65 Merge pull request 'feat(rust): ZLevels Remastered on the servers page (PLAN_REDESIGNS §14.3.6)' (#49) from feat/zlevels into edge
Reviewed-on: #49
2026-10-16 06:10:28 +00:00
9c82a0c437 feat(rust): ZLevels Remastered on the servers page (PLAN_REDESIGNS §14.3.6)
All checks were successful
PR Checks / client-build (pull_request) Successful in 25s
PR Checks / server-tests (pull_request) Successful in 31s
PR Checks / frozen-manifest (pull_request) Successful in 51s
Stage 7 of the §14.3 integration plan (D374): Server settings' plugin
line says whether ZLevels is loaded and that an event may lend its XP
boosts as permissions. The integrations schema gains zLevels; the
swagger fragment is regenerated. No leaderboard change, nothing stored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-15 18:27:57 -05:00
8be7e5607e Merge pull request 'feat(rust): Guarded Crate — feed, map, Warden, Place a guarded crate (PLAN_REDESIGNS §14.3.5)' (#48) from feat/guarded-crate into edge
Reviewed-on: #48
2026-10-15 23:19:14 +00:00
da1d74bdff feat(rust): Guarded Crate — feed, map, Warden, Place a guarded crate (PLAN_REDESIGNS §14.3.5)
All checks were successful
PR Checks / client-build (pull_request) Successful in 30s
PR Checks / server-tests (pull_request) Successful in 34s
PR Checks / frozen-manifest (pull_request) Successful in -1m34s
Stage 6 of the §14.3 integration plan, on protocol 14. Spec: docs
rust-link/PROTOCOL.md §20.9.

- gc.started and gc.ended public, gc.failed staff's; guardedCrate.js reads
  each row per viewer (the clearer's name for the presence audience, Steam id,
  position and key for staff, `won` for everyone).
- Triggers rust.gc.started and rust.gc.ended (a crate a player cleared only).
- The step rust.gc.place: an event from rust.options.gc_events and a world
  call's location; refused at verify for Guarded Crate absent, NpcSpawn missing
  (D364), console unavailable, or an unknown event. Kept (D373); the run log's
  success line says so (D380). Budget rust.gc.crates.
- Warden (D375): guarded_won, title category guardedwon, Crates cleared column.
- Map marker, server settings line, swagger, engagement manifest, bundle, README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-15 12:26:50 -05:00
140bc67fe1 Merge pull request 'feat(rust): Dangerous Treasures — feed, map, Treasure Hunter, Start a Dangerous Treasures event (PLAN_REDESIGNS §14.3.4)' (#47) from feat/dangerous-treasures into edge
Reviewed-on: #47
2026-10-15 12:04:31 +00:00
bfe9b5b18d feat(rust): Dangerous Treasures — feed, map, Treasure Hunter, Start a Dangerous Treasures event (PLAN_REDESIGNS §14.3.4)
All checks were successful
PR Checks / client-build (pull_request) Successful in 27s
PR Checks / frozen-manifest (pull_request) Successful in 46s
PR Checks / server-tests (pull_request) Successful in 7m23s
Stage 5 of the §14.3 integration plan, on protocol 14 (docs
rust-link/PROTOCOL.md §20.8).

- dt.started and dt.won are public kinds, dt.ended a staff kind. The new
  dangerousTreasures.js reads each row per viewer: grid and invaderCount for
  everyone, the winner's name for the presence audience (D376), the position,
  the step's key, the winner's Steam id and the invaders for staff.
- Feed lines in the World events filter: "A Dangerous Treasures event has
  started · K12", "Alice won the treasure · K12 · 3 players fought for it".
- Triggers rust.dt.started (with byEvent) and rust.dt.won, public, cooldown
  subject the server, names only.
- eventDangerousTreasures.js: rust.dt.start, "Start a Dangerous Treasures
  event" (risk change, reversible none, budget rust.dt.events), server and
  difficulty. Refused at verify where the server said DT is not loaded or
  console.plugins is false (Rust-Plugins#34). dt-not-ready answers "Dangerous
  Treasures is not ready yet" with retryAfterMs 600000 (D365, D371);
  dt-no-spot retries on core's delay; DT's own refusals are permanent.
- Treasure Hunter (D375): treasuresWon -> treasures_won, the title category
  treasureswon, and a sortable Treasures column shown where the server
  reports DT or a row counts one.
- The map draws a running chest on the world layer; the server settings'
  plugin line names DT and whether a step can start one, from the
  integrations read's new `console`.
- coreApi ^1.15.0, ci/core-ref.json pinned to website main at #215's merge.
  ci/bundle.json ships the two new files; swagger fragment and engagement
  manifest regenerated; README lists DT.

Server 627/627 (16 new in test/dangerousTreasures.test.js) and every check;
client 92/92, build and externals. Booted against the pinned core: 45
triggers, 13 actions, 11 budgets, 21 option sources; 89 routes unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-15 06:45:30 -05:00
6802dbf5f9 Merge pull request 'feat(rust): Dynamic PVP's zones on the feed and the map (PLAN_REDESIGNS §14.3.3)' (#46) from feat/dynamic-pvp into edge
Reviewed-on: #46
2026-10-15 11:17:59 +00:00
549b3a5ffd feat(rust): Dynamic PVP's zones on the feed and the map (PLAN_REDESIGNS §14.3.3)
All checks were successful
PR Checks / client-build (pull_request) Successful in 25s
PR Checks / server-tests (pull_request) Successful in 31s
PR Checks / frozen-manifest (pull_request) Successful in 44s
Stage 4 of the §14.3 integration plan, on protocol 14 (docs
rust-link/PROTOCOL.md §20.7).

- pvp.zone.created is a public kind, pvp.zone.deleted a staff kind. Each row
  is read per viewer by the new dynamicPvp.js: grid for everyone, the event's
  name only for Dynamic PVP's own vanilla events, position and zone id for
  staff only.
- The feed's world filter carries the opening: "A PvP zone opened around the
  downed patrol helicopter · G7 · for 10 min". It names nobody.
- The map gains a fifth layer, `pvp` (PvP zones), public by default with its
  own audience in Admin → Rust visibility, drawn as a red ring with its
  event's name.
- Server settings' plugin line names Dynamic PVP; the swagger schemas and
  route descriptions carry the layer and the integration (fragment
  regenerated); ci/bundle.json ships dynamicPvp.js; README lists it.

Tests: server 611/611 (dynamicPvp.test.js new, catalogue and map extended)
and every check; client 89/89 (feed and map tooltip), build and externals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-15 06:12:07 -05:00
b5f7fa0f13 Merge pull request 'feat(rust): TruePVE in the zone step — no PvP protection, or a ruleset (PLAN_REDESIGNS §14.3.2)' (#45) from feat/truepve-zone into edge
Reviewed-on: #45
2026-10-15 11:06:11 +00:00
e3cc95f8ab feat(rust): TruePVE in the zone step — no PvP protection, or a ruleset (PLAN_REDESIGNS §14.3.2)
All checks were successful
PR Checks / client-build (pull_request) Successful in 24s
PR Checks / frozen-manifest (pull_request) Successful in 44s
PR Checks / server-tests (pull_request) Successful in 7m23s
Stage 3 of the §14.3 integration plan (D362, D368), on protocol 14 (docs
rust-link/PROTOCOL.md §20.6).

- rust.zone.open gains noPvpProtection (boolean) and pvpRuleset (string),
  sent as world.zone's truePve { exclude: true } or { ruleset }.
- Both set, a name over 64 characters, or a server whose hello says TruePVE
  is not loaded is refused for good, at verify too. A server that has not
  said is left to the plugin, as a dome is.
- truepve-missing and truepve-ruleset are permanent failures, with the
  plugin's words.
- The zone servers list carries each server's truePve from hello; Server
  settings' plugin line says whether TruePVE is loaded; the integrations
  schema documents it (swagger fragment regenerated).
- README lists TruePVE among the optional plugins.

Tests: five new in zones.test.js; server 603/603 and all checks, client
84/84 and the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-15 05:48:00 -05:00
4af731288a feat: TruePVE in the zone step (PLAN_REDESIGNS §14.3.2, WIP)
Stage 3 of the §14.3 integration plan (D362, D368): world.zone's optional
truePve ({exclude: true} or {ruleset}), all or nothing, unmapped on every
path that erases one of our zones, with truepve.json for erases while
TruePVE is away. Docs and PRs still to come.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-15 03:03:36 -05:00