josh/tws-zombies-scripts#3 adds .b, .d and .w bank commands to the game scripts. Balances have to outlive a match, so Electric Cherry needs to store them by GUID and give the scripts an endpoint to read and change them. Nothing in Electric Cherry does this today.
access.ts:40-41 lets game servers in through two routes only: POST /api/telemetry (machine) and GET /api/leaderboard (public, read-only). Neither changes anything a player can spend.
auth/telemetry.ts:12-42 checks one shared secret, EC_TELEMETRY_TOKEN. The scripts carry it as a literal (tws_t5_telemetry.gsc:34 and tws_t6_telemetry.gsc:39 in josh/tws-zombies-scripts), so it's in that repo and in every deployed copy.
api/telemetry/+server.ts:60 takes the server name from the request body, and player GUIDs come from the body too, so the token holder can speak for any server and any player.
player-profile.ts:30 already shows one player per GUID across T5 and T6, while leaderboard_players stays keyed by game and GUID (docs/guides/leaderboard.md, "Player identity").
A bank endpoint is riskier than telemetry: whoever holds its credential can create points for any GUID, so reusing the shared telemetry token would let anyone with a copy of the scripts do that. Requests also fail and time out (the scripts send each report once, josh/tws-zombies-scripts#2), so a withdrawal Electric Cherry applied but the game never heard about would lose points, and a retried deposit would add them twice.
Fix
Store a balance per GUID, shared across T5 and T6 as player profiles are, and a ledger entry for every change (GUID, server, Electric Cherry match id when known, amount, resulting balance, time).
Add machine endpoints for the scripts to read a balance, deposit and withdraw, routed in access.ts like /api/telemetry.
Authenticate them with a credential per game server instead of EC_TELEMETRY_TOKEN, and refuse a request whose server name doesn't match its credential.
Refuse a deposit or withdrawal for a GUID that Electric Cherry hasn't recorded in that server's active match.
Each deposit and withdrawal carries a request id, and repeating an id returns the first result without applying it again.
Refuse a withdrawal larger than the balance, and a deposit that would take the balance over a configurable maximum, without changing anything.
Match retention and server deletion don't remove balances or ledger entries.
Show the balance and recent ledger entries on the player profile.
Document the endpoints, the credential and the limits in docs/guides/.
Add tests: a repeated request id applies once, overdraws and deposits over the maximum are refused, the telemetry token and another server's credential are refused, a GUID outside the server's active match is refused, and T5 and T6 share one balance.
[josh/tws-zombies-scripts#3](https://gitea.thewrightserver.net/josh/tws-zombies-scripts/issues/3) adds `.b`, `.d` and `.w` bank commands to the game scripts. Balances have to outlive a match, so Electric Cherry needs to store them by GUID and give the scripts an endpoint to read and change them. Nothing in Electric Cherry does this today.
- `access.ts:40-41` lets game servers in through two routes only: `POST /api/telemetry` (machine) and `GET /api/leaderboard` (public, read-only). Neither changes anything a player can spend.
- `auth/telemetry.ts:12-42` checks one shared secret, `EC_TELEMETRY_TOKEN`. The scripts carry it as a literal (`tws_t5_telemetry.gsc:34` and `tws_t6_telemetry.gsc:39` in josh/tws-zombies-scripts), so it's in that repo and in every deployed copy.
- `api/telemetry/+server.ts:60` takes the server name from the request body, and player GUIDs come from the body too, so the token holder can speak for any server and any player.
- `player-profile.ts:30` already shows one player per GUID across T5 and T6, while `leaderboard_players` stays keyed by game and GUID (`docs/guides/leaderboard.md`, "Player identity").
A bank endpoint is riskier than telemetry: whoever holds its credential can create points for any GUID, so reusing the shared telemetry token would let anyone with a copy of the scripts do that. Requests also fail and time out (the scripts send each report once, josh/tws-zombies-scripts#2), so a withdrawal Electric Cherry applied but the game never heard about would lose points, and a retried deposit would add them twice.
**Fix**
- [x] Store a balance per GUID, shared across T5 and T6 as player profiles are, and a ledger entry for every change (GUID, server, Electric Cherry match id when known, amount, resulting balance, time).
- [x] Add machine endpoints for the scripts to read a balance, deposit and withdraw, routed in `access.ts` like `/api/telemetry`.
- [x] Authenticate them with a credential per game server instead of `EC_TELEMETRY_TOKEN`, and refuse a request whose server name doesn't match its credential.
- [x] Refuse a deposit or withdrawal for a GUID that Electric Cherry hasn't recorded in that server's active match.
- [x] Each deposit and withdrawal carries a request id, and repeating an id returns the first result without applying it again.
- [x] Refuse a withdrawal larger than the balance, and a deposit that would take the balance over a configurable maximum, without changing anything.
- [x] Match retention and server deletion don't remove balances or ledger entries.
- [x] Show the balance and recent ledger entries on the player profile.
- [x] Document the endpoints, the credential and the limits in `docs/guides/`.
- [x] Add tests: a repeated request id applies once, overdraws and deposits over the maximum are refused, the telemetry token and another server's credential are refused, a GUID outside the server's active match is refused, and T5 and T6 share one balance.
Reviewed e071e5b574, d14c6a7ff4. All fix items are complete; closing this issue.
Checklist
Shared account and ledger. Migrations 20/21 add GUID accounts, request identities and a ledger; fleet/bank.ts updates them transactionally.
Machine API. POST balance/deposit/withdraw/commit/cancel routes use dedicated machine authentication.
Instance credentials. Credentials are generated per immutable instance, bound to the request server, preserved on rebuild and revoked on retirement. Telemetry credentials and cross-server requests are rejected.
Active membership. New transfers require a present GUID in the exact latest active reporter match.
Idempotency. Request fingerprints, durable results and a unique ledger identity prevent duplicate application; conflicting requests are rejected.
Limits. Overdraw, configurable bank maximum and game point capacity are checked before preparation; one prepared transfer per GUID serializes cross-server spending.
Retention. Account/ledger tables have no cascading match/server foreign keys; tests retain balances and settle prepared work after deletion.
Profile. Player profiles show balance, available/pending status and the latest 20 ledger entries, including expired match references.
Documentation.docs/guides/bank.md covers authentication, endpoints, limits, deployment and recovery.
Tests.bank.test.ts covers all requested cases plus cancellation-before-prepare, lost replies, DB reopen, rollback, concurrent preparations and scoped agent settlement.
Review notes
Reviewed current EC main at fa0baa8db5. Full application suite passed: 230 files, 3,120 tests, including migration-memory coverage; no failures or skips.
Python agent suite: 332 tests passed, no skips. Type/style checks: zero errors and warnings.
This closes the backend store/API scope, not the live game-bank rollout. Scripts #3/#13 still need live validation. The separate private-config drift/reconciliation defect remains tracked in EC #152 and is not resolved by these commits.
Reviewed e071e5b57432dcf6f354be9c65971e87b59dcf61, d14c6a7ff48e013b4ebe75b81c77424d50f188f5. All fix items are complete; closing this issue.
**Checklist**
- [x] **Shared account and ledger.** Migrations 20/21 add GUID accounts, request identities and a ledger; `fleet/bank.ts` updates them transactionally.
- [x] **Machine API.** POST balance/deposit/withdraw/commit/cancel routes use dedicated machine authentication.
- [x] **Instance credentials.** Credentials are generated per immutable instance, bound to the request server, preserved on rebuild and revoked on retirement. Telemetry credentials and cross-server requests are rejected.
- [x] **Active membership.** New transfers require a present GUID in the exact latest active reporter match.
- [x] **Idempotency.** Request fingerprints, durable results and a unique ledger identity prevent duplicate application; conflicting requests are rejected.
- [x] **Limits.** Overdraw, configurable bank maximum and game point capacity are checked before preparation; one prepared transfer per GUID serializes cross-server spending.
- [x] **Retention.** Account/ledger tables have no cascading match/server foreign keys; tests retain balances and settle prepared work after deletion.
- [x] **Profile.** Player profiles show balance, available/pending status and the latest 20 ledger entries, including expired match references.
- [x] **Documentation.** `docs/guides/bank.md` covers authentication, endpoints, limits, deployment and recovery.
- [x] **Tests.** `bank.test.ts` covers all requested cases plus cancellation-before-prepare, lost replies, DB reopen, rollback, concurrent preparations and scoped agent settlement.
**Review notes**
- Reviewed current EC main at fa0baa8db5f7629de3f58f2e6bf8da0568018be0. Full application suite passed: 230 files, 3,120 tests, including migration-memory coverage; no failures or skips.
- Python agent suite: 332 tests passed, no skips. Type/style checks: zero errors and warnings.
- This closes the backend store/API scope, not the live game-bank rollout. Scripts #3/#13 still need live validation. The separate private-config drift/reconciliation defect remains tracked in EC #152 and is not resolved by these commits.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
josh/tws-zombies-scripts#3 adds
.b,.dand.wbank commands to the game scripts. Balances have to outlive a match, so Electric Cherry needs to store them by GUID and give the scripts an endpoint to read and change them. Nothing in Electric Cherry does this today.access.ts:40-41lets game servers in through two routes only:POST /api/telemetry(machine) andGET /api/leaderboard(public, read-only). Neither changes anything a player can spend.auth/telemetry.ts:12-42checks one shared secret,EC_TELEMETRY_TOKEN. The scripts carry it as a literal (tws_t5_telemetry.gsc:34andtws_t6_telemetry.gsc:39in josh/tws-zombies-scripts), so it's in that repo and in every deployed copy.api/telemetry/+server.ts:60takes the server name from the request body, and player GUIDs come from the body too, so the token holder can speak for any server and any player.player-profile.ts:30already shows one player per GUID across T5 and T6, whileleaderboard_playersstays keyed by game and GUID (docs/guides/leaderboard.md, "Player identity").A bank endpoint is riskier than telemetry: whoever holds its credential can create points for any GUID, so reusing the shared telemetry token would let anyone with a copy of the scripts do that. Requests also fail and time out (the scripts send each report once, josh/tws-zombies-scripts#2), so a withdrawal Electric Cherry applied but the game never heard about would lose points, and a retried deposit would add them twice.
Fix
access.tslike/api/telemetry.EC_TELEMETRY_TOKEN, and refuse a request whose server name doesn't match its credential.docs/guides/.Reviewed
e071e5b574,d14c6a7ff4. All fix items are complete; closing this issue.Checklist
fleet/bank.tsupdates them transactionally.docs/guides/bank.mdcovers authentication, endpoints, limits, deployment and recovery.bank.test.tscovers all requested cases plus cancellation-before-prepare, lost replies, DB reopen, rollback, concurrent preparations and scoped agent settlement.Review notes
fa0baa8db5. Full application suite passed: 230 files, 3,120 tests, including migration-memory coverage; no failures or skips.