feat(rust): permissions as event rewards — lend or give any registered permission (PLAN_REDESIGNS §12)
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
This commit is contained in:
@@ -163,6 +163,8 @@ test('the event verbs are registered, and every budget has a verb that spends it
|
||||
'rust.npc.place',
|
||||
'rust.participation.collect',
|
||||
'rust.participation.open',
|
||||
'rust.perm.give',
|
||||
'rust.perm.lend',
|
||||
'rust.zone.open',
|
||||
])
|
||||
assert.deepStrictEqual(budgets.map((b) => b.id).sort(), [
|
||||
@@ -171,6 +173,8 @@ test('the event verbs are registered, and every budget has a verb that spends it
|
||||
'rust.coins',
|
||||
'rust.grants',
|
||||
'rust.npcs',
|
||||
'rust.permissions',
|
||||
'rust.permissions.kept',
|
||||
'rust.prefabs',
|
||||
'rust.zone.minutes',
|
||||
])
|
||||
@@ -182,7 +186,8 @@ test('the event verbs are registered, and every budget has a verb that spends it
|
||||
// operator. The two tally verbs spend nothing: counting people costs no loot.
|
||||
const spent = new Set()
|
||||
for (const a of actions) {
|
||||
const example = Object.fromEntries(a.params.map((p) => [p.name, p.example]))
|
||||
// A list param (MODULE_API 1.14.0) is priced as core prices it: its one example as a list of one.
|
||||
const example = Object.fromEntries(a.params.map((p) => [p.name, p.multiple ? [p.example] : p.example]))
|
||||
const dims = Object.keys(a.cost(example)).filter((id) => a.cost(example)[id] > 0)
|
||||
if (a.id.startsWith('rust.participation.')) {
|
||||
assert.strictEqual(dims.length, 0, `${a.id} prices ${dims.join(', ')}`)
|
||||
@@ -194,16 +199,17 @@ test('the event verbs are registered, and every budget has a verb that spends it
|
||||
assert.deepStrictEqual([...spent].sort(), budgets.map((b) => b.id).sort())
|
||||
|
||||
// What a teardown can give back is declared honestly: a line said, a
|
||||
// collect filed and coins paid (D335) are not undone.
|
||||
const once = new Set(['rust.announce', 'rust.participation.collect', 'rust.coins.pay'])
|
||||
// collect filed, coins paid (D335) and permissions given for good (D346) are
|
||||
// not undone.
|
||||
const once = new Set(['rust.announce', 'rust.participation.collect', 'rust.coins.pay', 'rust.perm.give'])
|
||||
for (const a of actions) {
|
||||
assert.strictEqual(a.reversible, once.has(a.id) ? 'none' : 'ledger', a.id)
|
||||
if (once.has(a.id)) continue
|
||||
assert.strictEqual(typeof a.revert, 'function')
|
||||
assert.strictEqual(typeof a.reconcile, 'function')
|
||||
// Every param source is one this module registers.
|
||||
const sources = new Set(api.record.eventOptionSources.map((s) => s.id))
|
||||
for (const p of a.params) if (p.source) assert.ok(sources.has(p.source), `${a.id}.${p.name} names ${p.source}`)
|
||||
if (once.has(a.id)) continue
|
||||
assert.strictEqual(typeof a.revert, 'function')
|
||||
assert.strictEqual(typeof a.reconcile, 'function')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user