feat(rust): permissions as event rewards — lend or give any registered permission (PLAN_REDESIGNS §12) #42

Merged
whitlocktech merged 1 commits from feat/rust-perm-rewards into edge 2026-10-12 20:03:41 -05:00
Member

Builds PLAN_REDESIGNS §12 (D342–D346, planned in docs#342). An event can now reward any permission a server's plugins registered: night vision, a chat colour, a /remove command. No perk-specific code. Both steps write rows the permission mirror already pushes, so there is no plugin, sidecar, protocol, installer or app change.

The steps

rust.perm.lend — Permissions until the event ends rust.perm.give — Permissions for good
Writes one rust_perm_run_grants row per recipient per permission (a kit reward's lease) one standing rust_perm_grants row per website user per permission, scoped to the step's server, source event, note "event run N, step M"
Risk change / ledger, with rust.kit.entitle's revert and reconcile irreversible / none, like rust.coins.pay
Budget rust.permissions — Permissions lent rust.permissions.kept — Permissions given for good
Message on one row per recipient a notice-only run-grant row (no permission, no kit, no credit)

Both steps share these rules:

  • Several permissions per step through core's new multiple param (website#213, MODULE_API 1.14.0), at most 10.
  • A required "I am sure" toggle (D343). Unticked, the dry run and the run refuse with Tick "I am sure" to make nightvision.allowed, betterchat.color a reward.
  • A permission missing from the server's catalogue is refused by name, never skipped. A server with no catalogue yet is a wait (retryable), not a refusal.
  • A blank message tells nobody. {permissions} puts in the names.
  • Give leaves a grant that is already there alone, and reports it as already held. A retry recognises its own first attempt's grants by the note, so nothing is counted twice.

Picker rust.options.permissions: every permission in the enabled servers' catalogues, grouped by the plugin that registered it. Unowned permissions are grouped as "<prefix> (not registered by a plugin)". Sorted by plugin, then by permission, ignoring case. A permission that is not on every server carries the note "Only on Main".

Permission manager: a for-good grant shows a given by event run N, step M chip. Staff turn it off like any other grant.

Checks

  • Server suite: 563/563. That includes the new test/permRewards.test.js (15). entry.test.js now lists the two verbs and budgets, prices a list param as core does, and checks the param sources of every verb, including the irreversible ones.
  • Client: 79/79, build OK, check:externals OK. check:imports, check:bundle (the new file is in ci/bundle.json), check:swagger and check:engagement all OK. engagement-triggers.json is regenerated for the new coreApi.
  • Real core: a core at website#213's head with this module installed registers it (11 actions, 9 budgets, 19 option sources).
    • The frozen manifest is current at 89 routes. routes.manifest.json is unchanged, since there are no new routes.
    • Core's own spec path validates and prices both steps:
      • duplicates dropped;
      • a bare value read as a list of one;
      • 11 permissions refused (holds 11 values; the most is 10);
      • none refused (is required);
      • confirm required;
      • 3 people × 2 permissions priced at 6.

ci/core-ref.json is pinned to website#213's branch head (743f1bc), because a 1.13.0 core refuses ^1.14.0. I'll re-pin it to #213's merge sha once that merges, as I did for #212.

The walk rows in §12.9 are deferred to the end-of-plan walk (D331).

  • AI-assisted: written with Claude Code (Claude Opus 5.5)

🤖 Generated with Claude Code

https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY

Builds **PLAN_REDESIGNS §12** (D342–D346, planned in docs#342). An event can now reward any permission a server's plugins registered: night vision, a chat colour, a `/remove` command. No perk-specific code. Both steps write rows the permission mirror already pushes, so there is **no plugin, sidecar, protocol, installer or app change**. ## The steps | | `rust.perm.lend` — *Permissions until the event ends* | `rust.perm.give` — *Permissions for good* | |---|---|---| | Writes | one `rust_perm_run_grants` row per recipient per permission (a kit reward's lease) | one standing `rust_perm_grants` row per website user per permission, scoped to the step's server, source `event`, note *"event run N, step M"* | | Risk | `change` / `ledger`, with `rust.kit.entitle`'s revert and reconcile | `irreversible` / `none`, like `rust.coins.pay` | | Budget | `rust.permissions` — *Permissions lent* | `rust.permissions.kept` — *Permissions given for good* | | Message | on one row per recipient | a notice-only run-grant row (no permission, no kit, no credit) | Both steps share these rules: - **Several permissions per step** through core's new `multiple` param (website#213, MODULE_API 1.14.0), at most 10. - **A required "I am sure" toggle** (D343). Unticked, the dry run and the run refuse with *Tick "I am sure" to make nightvision.allowed, betterchat.color a reward*. - **A permission missing from the server's catalogue is refused by name**, never skipped. A server with no catalogue yet is a wait (retryable), not a refusal. - **A blank message tells nobody.** `{permissions}` puts in the names. - Give leaves a grant that is already there alone, and reports it as *already held*. A retry recognises its own first attempt's grants by the note, so nothing is counted twice. **Picker `rust.options.permissions`:** every permission in the enabled servers' catalogues, grouped by the plugin that registered it. Unowned permissions are grouped as *"&lt;prefix&gt; (not registered by a plugin)"*. Sorted by plugin, then by permission, ignoring case. A permission that is not on every server carries the note *"Only on Main"*. **Permission manager:** a for-good grant shows a *given by event run N, step M* chip. Staff turn it off like any other grant. ## Checks - **Server suite: 563/563.** That includes the new `test/permRewards.test.js` (15). `entry.test.js` now lists the two verbs and budgets, prices a list param as core does, and checks the param sources of every verb, including the irreversible ones. - **Client: 79/79**, build OK, `check:externals` OK. `check:imports`, `check:bundle` (the new file is in `ci/bundle.json`), `check:swagger` and `check:engagement` all OK. `engagement-triggers.json` is regenerated for the new `coreApi`. - **Real core:** a core at website#213's head with this module installed registers it (11 actions, 9 budgets, 19 option sources). - The frozen manifest is current at 89 routes. `routes.manifest.json` is unchanged, since there are no new routes. - Core's own spec path validates and prices both steps: - duplicates dropped; - a bare value read as a list of one; - 11 permissions refused (*holds 11 values; the most is 10*); - none refused (*is required*); - `confirm` required; - 3 people × 2 permissions priced at 6. **`ci/core-ref.json` is pinned to website#213's branch head (`743f1bc`)**, because a 1.13.0 core refuses `^1.14.0`. I'll re-pin it to #213's merge sha once that merges, as I did for #212. The walk rows in §12.9 are deferred to the end-of-plan walk (D331). - [x] AI-assisted: written with Claude Code (Claude Opus 5.5) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 1 commit 2026-10-12 15:50:05 -05:00
feat(rust): permissions as event rewards — lend or give any registered permission (PLAN_REDESIGNS §12)
All checks were successful
PR Checks / client-build (pull_request) Successful in 20s
PR Checks / server-tests (pull_request) Successful in 27s
PR Checks / frozen-manifest (pull_request) Successful in -1m32s
63c82d5a2f
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
whitlocktech merged commit aefd752372 into edge 2026-10-12 20:03:41 -05:00
whitlocktech deleted branch feat/rust-perm-rewards 2026-10-12 20:03:43 -05:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/Module-Rust#42
No description provided.