fix(rust): send reward notices, and keep a downed line's credit rule (W21, W4)
All checks were successful
PR Checks / client-build (pull_request) Successful in 21s
PR Checks / frozen-manifest (pull_request) Successful in 48s
PR Checks / server-tests (pull_request) Successful in 7m16s

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:
2026-10-21 06:16:32 -05:00
parent 5decd5cc05
commit 8aff9b33a6
7 changed files with 92 additions and 15 deletions

View File

@@ -314,13 +314,7 @@ async function syncOne(server, { authored, sync, state, force, policy = 'auto-ad
held: planned.hold.size,
})
const result = await sidecar.permSync(server, {
setId: desired.hash,
groups: withExpect(held.payload.groups, pushed),
grants: held.payload.grants,
credits: held.payload.credits,
retire,
})
const result = await sidecar.permSync(server, pushBody(desired.hash, held.payload, pushed, retire))
if (!result.ok) {
await failed(server, { reason, error: result.status, desiredHash: desired.hash, sync, bootId, wipeId })
@@ -358,6 +352,23 @@ async function syncOne(server, { authored, sync, state, force, policy = 'auto-ad
return 'ok'
}
/**
* The sync as the wire carries it: every field of the built payload, the
* groups with their style `expect`s, and what to retire. `notices` rides here
* too (D333) — the push once named its fields one by one and left it out, so
* no reward message ever reached the game (W21).
*/
function pushBody(setId, payload, pushed, retire) {
return {
setId,
groups: withExpect(payload.groups, pushed),
grants: payload.grants,
credits: payload.credits,
notices: payload.notices,
retire,
}
}
/**
* The groups as the wire carries them: each style field with the value this
* site last pushed to THIS server (`expect`), or null for one it never has.
@@ -526,6 +537,7 @@ module.exports = {
syncOne,
reasonToSync,
applyReport,
pushBody,
withExpect,
styleRetirements,
withLock,