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
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
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
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
#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
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
website#213 (MODULE_API 1.14.0, the `multiple` param) merged as a981b2b.
Its tree is identical to the branch head 743f1bc this was pinned to, so
routes.manifest.json is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
D342-D346 (docs#342). Two steps over the permission mirror's own tables, so
no plugin, sidecar or protocol change:
- rust.perm.lend, "Permissions until the event ends": a kit reward's lease,
one rust_perm_run_grants row per recipient per permission, the message on
one row each; change/ledger with rust.kit.entitle's revert and reconcile;
budget rust.permissions.
- rust.perm.give, "Permissions for good": a standing rust_perm_grants row per
website user per permission, scoped to the step's server, source `event`,
note "event run <run>, step <step>"; a grant already there is left alone,
and a retry's own grants are counted as given; the message rides a
notice-only run-grant row; irreversible/none; budget rust.permissions.kept.
- Both: several permissions through core's `multiple` param (MODULE_API
1.14.0, at most 10); a required "I am sure" toggle refused unticked in the
dry run and at run time, naming the permissions (D343); a permission the
server's catalogue lacks refused by name; a blank message tells nobody.
- rust.options.permissions: the enabled servers' catalogues, grouped by the
registering plugin (by prefix when none), sorted plugin then permission
without case, a row noted "Only on X" when not on every server.
- Permission manager: an event-given grant shows "given by event run N,
step M"; staff turn it off like any grant.
- coreApi ^1.14.0; ci/core-ref.json pinned to website#213's head until it
merges; engagement-triggers.json regenerated; routes.manifest.json
unchanged (no new routes).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
website#212 (MODULE_API 1.13.0) merged as ca7ec53, whose tree is the
same as the branch head e58857c this repo was pinned to while it was
open. Only the pin moves; routes.manifest.json is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
PLAN_REDESIGNS §2, the Rust half (D164, D192, D332, D333):
- rust.template.kit_weekend (core registerEventTemplates, MODULE_API 1.13.0):
inputs kit/minutes/message/delivery; one phase advance after the weekend,
core.lease rust.group.permission default/<kit permission> + rust.kit.entitle
linked. Steps only where the kit can use them; validated by the real core.
- rust.kit.entitle: recipients 'linked' (every linked player who has played
on the server, no tally, refused past the bound), optional message ({kit})
and delivery, stored per row (rust_perm_run_grants.notice*).
- perm.sync notices: the untold set to the picked account, keyed
run:step:user, in the digest; the report's noticesTold marks them told.
- rust.options.grouppermissions notes a kit's permission rows via kits.uses
(cached a minute per server; a failure is no note).
- duration: 'minutes' on rust.zone.open and rust.participation.open; the
group-permission lease's value example is true.
- protocol 13 -> 14, coreApi ^1.13.0; ci/core-ref.json pinned to website#212's
head while it is open; engagement-triggers.json regenerated (coreApi line).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
The job cloned a MODULE_API 1.10.0 main and the loader refused the module
("needs core API ^1.11.0, this core is 1.10.0"), so it added no routes and
failed by construction. Pinned to #209's head (cc1f49a), where the job's own
steps pass: core alone 280 routes up to date, with this module 49 routes all
documented. Re-pin to #209's main merge sha once it lands.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Phase 2 of docs/modules/rust/PLAN.md. Phase 1 built five guards and ran them by
hand; this repo had no workflows at all, so nothing gated the branch that gets
released and there was no way to release it.
Three pieces:
- **release.yml** — the derived-version engine link, installer and Module-uo
already run (conventional-commit subjects since the newest tag; module.json's
version survives as a floor; workflow_dispatch as the backdoor), assembling the
bundle from an include list and publishing the tarball, the install manifest
carrying its sha256, and SHA256SUMS. The tag is the number that ships and CI
stamps it into the bundle's own module.json.
- **pr-checks.yml** — server tests, check:imports, check:bundle, check:swagger,
the client build, client tests and check:externals, plus frozen-manifest.
- **frozen-manifest** — clones core at the sha pinned in ci/core-ref.json,
generates its route table without this module and with it, and takes the
difference. It ran locally against that exact ref: six routes, all documented,
no core route moved. That is the first proof by a running core that /rust
collides with nothing — phase 1 could only check it by reading, because core
mounts /status and /version at a tier root where the loader's own collision
probe cannot see them.
The bundle carries no node_modules, because the shipped half declares no runtime
dependencies (org lead, phase 2). checkBundle.js holds both halves of that: the
include list still covers everything server/index.js reaches, and no dependency
has appeared without the release learning to pack it. Verified by breaking it —
dropping "model" from the list names the exact edit and exits 1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4