feat(rust): the world verbs, their budgets and the reconcile watch (phase 13a, protocol 9)
- registerEventActions: rust.zone.open and rust.prefab.place, both reversible 'ledger' with revert() and reconcile(), budgetMs 15000 above the client's 12 s. A location is a monument (kind + instance, carrying its server) or raw coordinates, exactly one (D87, D93); bounds mirrored from the plugin so a bad step is refused on the form (D95); zone minutes required and held by the game (D96). - registerEventBudgets: rust.prefabs, rust.npcs and rust.zone.minutes, each beside the verb that spends it (D79, D89). - Option sources rust.options.monuments (live, searchable) and rust.options.prefabs (mirrored, answers with every server off), registered in the one batch core accepts alongside the lease sources. - Refs are <serverId>:<id>, since revert and reconcile get no params. The undo sends no idempotency key; a lost answer is reverted by key on every server. reconcile asks the plugin, and a server that cannot be asked keeps its rows. - The refresh's bootId/wipeId watch calls ctx.events.reconcile() on a restart or a wipe, never on a first sighting or a reconnect (§11.1). - The permission mirror keeps the plugin's new notLanded grants out of what it records as pushed, and the admin page says so (D85). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -205,6 +205,43 @@ test('a permission the server could not resolve is not recorded as pushed', asyn
|
||||
assert.ok(!recorded.includes('7656003'), 'a pending membership is not in the game yet')
|
||||
})
|
||||
|
||||
test('a grant the store did not hold after the plugin read it back is not recorded as pushed (D85)', async () => {
|
||||
const queries = withCore()
|
||||
const permSync = require('../permSync')
|
||||
|
||||
const desired = {
|
||||
hash: 'h1',
|
||||
rows: [
|
||||
{ kind: 'grant', subject: '7656001', object: 'kits.gold' },
|
||||
{ kind: 'grant', subject: '7656001', object: 'zonemanager.zone' },
|
||||
{ kind: 'group-permission', subject: 'vip', object: 'kits.vip' },
|
||||
],
|
||||
}
|
||||
|
||||
// Protocol 9's read-back. The case it exists for is phase 7's owner bug: a
|
||||
// grant the plugin made that never reached Oxide's store, which the site had
|
||||
// been recording as pushed.
|
||||
const report = {
|
||||
kind: 'perm.report',
|
||||
applied: { grants: 1 },
|
||||
unresolved: [],
|
||||
pending: [],
|
||||
notLanded: ['7656001:ZoneManager.Zone', 'vip:kits.vip'],
|
||||
foreign: [],
|
||||
}
|
||||
|
||||
const sidecar = require('../sidecarClient')
|
||||
sidecar.permCatalogue = async () => ({ ok: false, status: 'no-token', data: null })
|
||||
|
||||
await permSync.applyReport({ id: 'main' }, { desired, retire: [], report, bootId: null, wipeId: null })
|
||||
|
||||
const insert = queries.find((q) => q.sql.startsWith('INSERT IGNORE INTO rust_perm_pushed'))
|
||||
const recorded = insert.params.join(' ')
|
||||
assert.ok(recorded.includes('kits.gold'), 'a grant that landed is pushed')
|
||||
assert.ok(!recorded.includes('zonemanager.zone'), 'a grant that did not land is not, whatever its case')
|
||||
assert.ok(!recorded.includes('kits.vip'), 'nor a group permission that did not land')
|
||||
})
|
||||
|
||||
test('a restart, a wipe and a hand edit each provoke a sync; a quiet server does not', () => {
|
||||
withCore()
|
||||
const permSync = require('../permSync')
|
||||
|
||||
Reference in New Issue
Block a user