fix(rust): the last fixes' small ones (W3 W6 W7/W11 W8 W10 W13-W18)
All checks were successful
PR Checks / client-build (pull_request) Successful in 24s
PR Checks / server-tests (pull_request) Successful in 32s
PR Checks / frozen-manifest (pull_request) Successful in 44s

Stage 2 of PLAN_LAST_FIXES (docs#366).

- W7/W11: an "is it loaded" refusal is confirmed live before it is given.
  New liveStatus.js asks the sidecar once (boot.refreshOne, as a poll tick
  would), at most once per server per 5 s and waiting at most 3 s, then
  reads the stored status again. Used by Economics (step and staff page),
  Backpacks, Dangerous Treasures, Guarded Crate, RaidableBases, ZoneDomes,
  TruePVE and RunicNPC.
- W3: a world call answered `already-out` (the bridge half comes in stage
  3) succeeds as called 0, saying a Travelling Vendor is already out.
- W6: "A locked crate dropped by a Chinook is being hacked."
- W8: a RaidableBases profile's audit row names RaidableBases, not "@data".
- W10: the backpack sizes picker lists each size once, naming its servers.
- W13: a RaidableBases name both servers describe differently shows each
  server's own description.
- W14: each RaidableBases note after the first starts its own sentence.
- W15: a staff deposit refused at Economics' limit answers 409.
- W16: a payment's failedNote explains only the reasons that happened.
- W17: the sync state counts player grants that did not land
  (waitingToLand), and the Permissions page says "in sync · 1 waits for
  their player to join" instead of plain "in sync".
- W18: Guarded Crate's kept note drops the "30 minutes" it could not know.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-21 07:42:24 -05:00
parent d69c2108c6
commit 3aa142bf06
29 changed files with 479 additions and 41 deletions

View File

@@ -34,6 +34,10 @@ function withRecorder(rows = []) {
withRecorder()
// The stored status is the whole answer in these tests: nothing asks a
// sidecar before a refusal (W7, W11). liveStatus.test.js covers the ask.
require('../liveStatus').refresh = async () => false
const client = require('../sidecarClient')
const serversDb = require('../model/servers/servers.db')
const servers = require('../model/servers/servers.model')
@@ -220,10 +224,21 @@ test('coins go once to each website user, with the key, the amount and the messa
assert.strictEqual(result.detail.total, 500)
assert.deepStrictEqual(result.detail.received, [{ name: 'p1', received: 500 }])
assert.deepStrictEqual(result.detail.failed, [{ name: 'p4', reason: 'at-limit' }])
assert.strictEqual(result.detail.failedNote, "at-limit: the balance is at Economics' limit", 'only the reason that happened (W16)')
assert.deepStrictEqual(result.detail.missed, ['p3'])
assert.strictEqual(result.resources, undefined, 'nothing is ledgered')
})
test('a payment’s failedNote explains each reason that happened, and only those (W16)', () => {
const { failedNote } = require('../eventRewards')
assert.strictEqual(failedNote([{ reason: 'unmeasured' }, { reason: 'unmeasured' }]), 'unmeasured: Economics did not report the deposit')
assert.strictEqual(
failedNote([{ reason: 'unmeasured' }, { reason: 'at-limit' }, { reason: 'refused' }]),
"at-limit: the balance is at Economics' limit; refused: Economics did not take the deposit; unmeasured: Economics did not report the deposit",
)
assert.strictEqual(failedNote([{ reason: 'odd' }]), "odd: Economics' own reason")
})
test('a repeated key is answered from the first payment, and a lost answer is retried', async (t) => {
const person = { steamId: A, name: 'pa', seconds: 60, kills: 0, score: 1, joinedAt: 1 }
stub(t, { people: [person], links: { [A]: 1 }, payAnswer: () => ok({ kind: 'economics.paid', repeat: true, paid: [{ steamId: A, before: 1000, after: 1500 }], failed: [] }) })
@@ -291,6 +306,12 @@ test('a withdrawal above the balance is refused with the balance', async (t) =>
assert.match(result.message, /only 340 coins on Main/)
assert.deepStrictEqual(sent, [{ key: 'adj-1', steamId: A, op: 'withdraw', amount: 500 }])
// A deposit refused at the balance limit is the game saying no too (W15).
client.economicsAdjust = async () => ok({ kind: 'economics.error', reason: 'at-limit', message: "this player's balance is at Economics' limit" })
const capped = await economics.adjust({ serverId: 'main', steamId: A, op: 'deposit', amount: 50, key: 'adj-3' })
assert.strictEqual(capped.status, 409)
assert.strictEqual(capped.reason, 'at-limit')
economicsDb.reportFor = async () => null
const missing = await economics.adjust({ serverId: 'main', steamId: A, op: 'deposit', amount: 5, key: 'adj-2' })
assert.strictEqual(missing.status, 409)