feat(registry): awards ledger, stat totals, session-verified accounts and botmatch results #21

Merged
kblack0610 merged 1 commit from feat/registry-awards into main 2026-11-04 21:37:36 +00:00
Owner

DodginBalls rewards-admin P5 (plan: unity-core-playground/dodginballs-rewards-admin.md). Registry side of the awards system, deployed before the game posts to it (P6).

  • Migration 0008_rewards.sql: accounts.title, session_accounts, awards (append-only ledger, unique idem), stats (running sums per game and *, by tier). All cascade on account delete.
  • POST /api/v1/entitlements/ticket?session=<id> signs the session as aud; POST /api/v1/entitlements/verify with {ticket, session} and that session's lease records the account against the session. Plain verify is unchanged.
  • POST /api/v1/awards: token plus the session's lease; every account must be verified by the session (else 403). Tier from the token; hosted capped by AWARDS_HOSTED_PER_DAY (default 500) and never unlocks; unlocks only for active kind=reward catalog items, granted as an entitlement with source reward. seq makes a retry grant once. 30 posts per session per minute.
  • GET /api/v1/stats/me, GET /api/v1/awards/me?since=<id>.
  • POST /api/v1/results kind=botmatch: bots as {"id":"bot"}, not stored as players, no Elo; with session and its lease, verified humans on the sole winning side get a win.<mode> award.
  • README: Rewards section, routes, config row, results.

assumed: migration is 0008, not the plan's 0005, because 0005 to 0007 already shipped.
assumed: counts are [{key, amount}], not a map, because Unity's JsonUtility cannot write maps.
assumed: awards and verify-with-session always require the session lease (new routes, no old clients), checked against server_sessions so it holds after deregister.
assumed: the ticket audience is the session id (the plan's security note), so a host cannot replay a joiner's ticket to another server.
assumed: the hosted cap counts amount per UTC day; over it, counts are clipped and reported as capped.
assumed: botmatch wins live in the ledger and stats as win.<mode>; ratings stay for ranked matches only.
assumed: no title route, admin stat edit, revoke or admin view of stats here (P7, P8).

Checks: gofmt and go vet clean; go test ./... 132 pass / 0 fail against real Postgres and MinIO (6 new: verified awards and unlocks, hosted cap without unlocks, lease and verification refusals, botmatch wins without ratings, hosted botmatch cap, account delete takes awards). Forgejo has no PR CI for this repo; that local run is the gate.

Not deployed: needs a registry-v* tag and the home-config image bump (human-only), plus ENTITLEMENT_SECRET on the deployed registry.

https://claude.ai/code/session_01AWkPstXg5XSSwLrRRmfZJx

DodginBalls rewards-admin P5 (plan: unity-core-playground/dodginballs-rewards-admin.md). Registry side of the awards system, deployed before the game posts to it (P6). - Migration `0008_rewards.sql`: `accounts.title`, `session_accounts`, `awards` (append-only ledger, unique `idem`), `stats` (running sums per game and `*`, by tier). All cascade on account delete. - `POST /api/v1/entitlements/ticket?session=<id>` signs the session as `aud`; `POST /api/v1/entitlements/verify` with `{ticket, session}` and that session's lease records the account against the session. Plain verify is unchanged. - `POST /api/v1/awards`: token plus the session's lease; every account must be verified by the session (else 403). Tier from the token; hosted capped by `AWARDS_HOSTED_PER_DAY` (default 500) and never unlocks; unlocks only for active `kind=reward` catalog items, granted as an entitlement with source `reward`. `seq` makes a retry grant once. 30 posts per session per minute. - `GET /api/v1/stats/me`, `GET /api/v1/awards/me?since=<id>`. - `POST /api/v1/results` `kind=botmatch`: bots as `{"id":"bot"}`, not stored as players, no Elo; with `session` and its lease, verified humans on the sole winning side get a `win.<mode>` award. - README: Rewards section, routes, config row, results. assumed: migration is 0008, not the plan's 0005, because 0005 to 0007 already shipped. assumed: counts are `[{key, amount}]`, not a map, because Unity's JsonUtility cannot write maps. assumed: awards and verify-with-session always require the session lease (new routes, no old clients), checked against `server_sessions` so it holds after deregister. assumed: the ticket audience is the session id (the plan's security note), so a host cannot replay a joiner's ticket to another server. assumed: the hosted cap counts amount per UTC day; over it, counts are clipped and reported as `capped`. assumed: botmatch wins live in the ledger and stats as `win.<mode>`; ratings stay for ranked matches only. assumed: no title route, admin stat edit, revoke or admin view of stats here (P7, P8). Checks: gofmt and go vet clean; go test ./... 132 pass / 0 fail against real Postgres and MinIO (6 new: verified awards and unlocks, hosted cap without unlocks, lease and verification refusals, botmatch wins without ratings, hosted botmatch cap, account delete takes awards). Forgejo has no PR CI for this repo; that local run is the gate. Not deployed: needs a registry-v* tag and the home-config image bump (human-only), plus ENTITLEMENT_SECRET on the deployed registry. https://claude.ai/code/session_01AWkPstXg5XSSwLrRRmfZJx
Migration 0008_rewards: accounts.title, session_accounts, awards, stats.
POST /api/v1/awards (token + session lease), GET /api/v1/stats/me, GET /api/v1/awards/me.
Tickets carry an optional session audience; verify with {ticket, session} records the account.
POST /api/v1/results takes kind=botmatch: no Elo, win.<mode> awards to verified winners.

Claude-Session: https://claude.ai/code/session_01AWkPstXg5XSSwLrRRmfZJx
kblack0610 deleted branch feat/registry-awards 2026-11-04 21:37:36 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kblack0610/bnb-game-servers!21
No description provided.