fix(rust): send reward notices, and keep a downed line's credit rule (W21, W4)
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
This commit is contained in:
@@ -28,6 +28,7 @@ const rewards = require('../eventRewards')
|
||||
const leases = require('../eventLeases')
|
||||
const templates = require('../eventTemplates')
|
||||
const model = require('../model/permissions/permissions.model')
|
||||
const reconcile = require('../model/permissions/reconcile')
|
||||
|
||||
const entitle = rewards.ACTIONS.find((a) => a.id === 'rust.kit.entitle')
|
||||
const ok = (data) => ({ ok: true, status: 'ok', data })
|
||||
@@ -163,6 +164,19 @@ test('the sync carries each untold message to the account the reward picked', ()
|
||||
])
|
||||
})
|
||||
|
||||
test('the push carries the notices, and every other field the payload built (W21)', () => {
|
||||
const permSync = require('../permSync')
|
||||
const desired = model.buildDesired('main', authored([grantRow({ notice: 'You earned kit vip', noticeDelivery: 'chat' })]))
|
||||
const held = reconcile.withHold(desired, new Set())
|
||||
const body = permSync.pushBody(desired.hash, held.payload, [], [])
|
||||
assert.deepStrictEqual(body.notices, [
|
||||
{ key: '7:3:11', steamId: '76561190000000001', message: 'You earned kit vip', delivery: 'chat' },
|
||||
])
|
||||
// A field the model adds and the push forgets is how W21 happened.
|
||||
for (const field of Object.keys(held.payload)) assert.ok(field in body, `the push drops payload.${field}`)
|
||||
assert.strictEqual(body.setId, desired.hash)
|
||||
})
|
||||
|
||||
test('a notice moves the digest, so a new one is pushed and a told one is dropped', () => {
|
||||
const none = model.buildDesired('main', authored([grantRow({})]))
|
||||
const one = model.buildDesired('main', authored([grantRow({ notice: 'hi', noticeDelivery: 'chat' })]))
|
||||
|
||||
@@ -216,6 +216,19 @@ test('a Bradley counts toward Tankbreaker, and an arrival counts nothing', async
|
||||
assert.strictEqual(rec2.touching('rust_player_wipe_stats').length, 0)
|
||||
})
|
||||
|
||||
test('a downed one is stored with the rule that credited it; an arrival is stored as sent (W4)', async () => {
|
||||
const { apply } = require('../ingest')
|
||||
const storedRaw = async (frame) => {
|
||||
const rec = withRecorder()
|
||||
await apply('main', { id: 1, kind: 'world.event', frame }, { id: 'main', creditRule: 'all' })
|
||||
const insert = rec.touching('rust_events').find((s) => /INSERT/i.test(s.sql))
|
||||
return JSON.parse(insert.params.find((p) => typeof p === 'string' && p.startsWith('{')))
|
||||
}
|
||||
|
||||
assert.strictEqual((await storedRaw(downed())).creditRule, 'all')
|
||||
assert.strictEqual((await storedRaw(world('heli.arrived', { x: 1, z: 1 }))).creditRule, undefined)
|
||||
})
|
||||
|
||||
test('the tally’s crates hacked and drops looted are added up (D356)', async () => {
|
||||
const rec = withRecorder()
|
||||
const { apply } = require('../ingest')
|
||||
@@ -251,6 +264,21 @@ test('the feed reads each world event for its viewer, with the server’s rule a
|
||||
assert.deepStrictEqual(member.frame.credited, [{ name: 'Bob' }])
|
||||
})
|
||||
|
||||
test('a line keeps the rule it was stored with after the server’s rule changes (W4)', async () => {
|
||||
const stamped = downed({ creditRule: 'all' })
|
||||
withRecorder((sql) => {
|
||||
if (sql.includes('FROM rust_events')) return [{ id: 9, kind: 'world.event', t: NOW, wipeId: 'w1', steamId: null, raw: JSON.stringify(stamped) }]
|
||||
if (sql.includes('FROM rust_servers')) return [{ id: 'main', name: 'Main', creditRule: 'most', enabled: 1 }]
|
||||
return []
|
||||
})
|
||||
const events = require('../model/events/events.model')
|
||||
|
||||
const [member] = await events.recent({ serverId: 'main', presence: true })
|
||||
assert.strictEqual(member.frame.creditRule, 'all')
|
||||
assert.strictEqual(member.frame.creditedCount, 2)
|
||||
assert.deepStrictEqual(member.frame.credited.map((c) => c.name).sort(), ['Alice', 'Bob'])
|
||||
})
|
||||
|
||||
// ── Triggers (D355) ────────────────────────────────────────────────────────
|
||||
|
||||
test('one public trigger per type, none of them declaring a Steam id', () => {
|
||||
|
||||
Reference in New Issue
Block a user