# Certification checklist

**Operator:** ____________________
**Environment:** ____________________
**Transport Binding:** [ ] HTTP/JSON v2 &nbsp;&nbsp;&nbsp; [ ] Native gRPC v2
**Execution Date:** ____________________
**GA Certification Engineer:** ____________________
**Operator Lead Engineer:** ____________________

---

## 0. Scope of certification

A **PASS** here means one thing: your wallet endpoint follows the v2 contract on a test player. This includes the money rules that certification can exercise (idempotency, order of checks, rollback barrier, never-refused credits). It's a necessary condition for go-live, not the whole of it.

It does **not** prove:

- that your production wallet, with its own URL, credentials, and infrastructure, behaves the same. Run the tool against production before go-live.
- that your calls **to** GA work: game launch, catalog, free rounds, reports. Cover them with the `GA_Aggregator_API_v2` Postman collection and one real end-to-end session in the sandbox. Launch a game, place a bet, and see it in `rounds` and in the Operator Portal.
- that the numbers reconcile: compare one day of `aggregates` with your own ledger before the first settlement.
- performance under load: the tool sends one call at a time. Your wallet must answer every call within 5 seconds at your peak traffic.

Go-live needs all four plus this signed checklist.

### Files you need

| What | Where |
|---|---|
| Certification checks | Operator Portal → **Integration** → **Callback test** (`operator_admin` role, wallet URL with `/v2`). The same suite as the command-line tool `ga-operator-certify`, which your GA integration manager provides for CI runs |
| Postman: the calls GA sends to your wallet | `../postman/GA_Operator_API_v2.postman_collection.json` + `../postman/GA_Sandbox_v2.postman_environment.json` |
| Postman: your calls to GA | `../postman/GA_Aggregator_API_v2.postman_collection.json`, `../postman/GA_Features_API_v2.postman_collection.json` |
| All the above in one zip | `/downloads/GA_Operator_Integration_Pack_v2.0.0.zip` on the docs site |
| The guide | `/docs` on the docs site, or `GA_Operator_Integration_Guide_v2.pdf` in the zip |

---

## 1. Conformance tooling verification

### Prerequisites to confirm before running
- A dedicated test player exists in the operator wallet under the `--player-ref` passed to the tool (default `certify-player-001`) with a funded balance in the `--currency` (default `EUR`).
- You issue a valid launch token for that player and pass it via `--launch-token` (default `token-cert-001`). The tool doesn't create players or tokens.
- The API key/secret pair passed via `--api-key`/`--secret` is the one the wallet validates signatures with.
- The target is a sandbox/staging wallet, never production.

Certification requires one run in which every check passes: either from the Operator Portal (Integration → Callback test) or with `ga-operator-certify`, a binary your GA integration manager provides:

```bash
# HTTP Binding:
./ga-operator-certify --binding http --target https://wallet.operator.example --api-key <key-id> --secret <secret> --strict

# gRPC Binding:
./ga-operator-certify --binding grpc --target wallet.operator.example:9090 --api-key <key-id> --secret <secret> --strict

```

---

## 2. Test cases & obligations (all 55 `W2-*` checks)

### 2.1 Money primitives & idempotency
- [ ] `W2-G1-OPID-REQUIRED`: Your wallet refuses an empty `op_id` with `INVALID_REQUEST`.
- [ ] `W2-G1-DEBIT-ANSWER-SHAPE`: A debit answer carries `operator_tx_id` and `balance_after`.
- [ ] `W2-G1-OPID-REPLAY-MOVES-MONEY-ONCE`: Replaying an `op_id` returns stored result and does NOT move money twice.
- [ ] `W2-G1-TWO-WINS-ONE-ROUND-BOTH-SETTLE`: Two Credits in one `round_id` with distinct `op_ids` both settle.
- [ ] `W2-DEBIT-INSUFFICIENT-FUNDS`: A debit exceeding balance answers business refusal `INSUFFICIENT_FUNDS`.
- [ ] `W2-DEBIT-ZERO-AMOUNT`: Your wallet refuses a debit with zero amount as `INVALID_REQUEST`.
- [ ] `W2-CREDIT-ZERO-AMOUNT`: A credit with zero amount succeeds cleanly without altering balance.
- [ ] `W2-KIND-EACH-CREDIT-KIND-ACCEPTED`: Credit accepts all defined `CreditKind` variants (WIN, BONUS, JACKPOT, PROMO, FREE_ROUND, TOURNAMENT, CASHBACK, ADJUSTMENT).
- [ ] `W2-COMPONENTS-SUM-EQUALS-AMOUNT`: A credit with `MoneyComponent` breakdown matches total amount.

### 2.2 Atomic debit & credit
- [ ] `W2-DEBITCREDIT-HAPPY`: Atomic `DebitCredit` applies net difference to player balance.
- [ ] `W2-DEBITCREDIT-INSUFFICIENT`: Atomic `DebitCredit` with bet > balance refuses with `INSUFFICIENT_FUNDS`.
- [ ] `W2-DEBITCREDIT-ATOMIC-ON-CREDIT-FAILURE`: Atomic `DebitCredit` leaves balance intact if operation can't complete.
- [ ] `W2-DEBITCREDIT-REPLAY`: Atomic `DebitCredit` replayed returns identical stored response.

### 2.3 Reversals & rollbacks
- [ ] `W2-G4-ROLLBACK-IDEMPOTENT-ON-ITS-OWN-OPID`: The same Rollback delivered twice reverses exactly once.
- [ ] `W2-G4-ROLLBACK-OF-UNKNOWN-ORIGINAL-IS-OK-NOOP`: A Rollback naming an unknown original answers OK and moves nothing.
- [ ] `W2-G4-DEBIT-AFTER-ROLLBACK-OF-UNKNOWN-REJECTED`: Your wallet rejects a Debit whose `op_id` it already rolled back as an unknown original. The barrier holds.
- [ ] `W2-ROLLBACK-PARTIAL`: A Rollback with partial amount reverses only specified amount.
- [ ] `W2-ROLLBACK-DEBIT-MODE-REJECT`: Rollback with `debit_mode=REJECT` refuses if balance insufficient.
- [ ] `W2-ROLLBACK-DEBIT-MODE-ALLOW_NEGATIVE`: Rollback with `debit_mode=ALLOW_NEGATIVE` permits negative balance.
- [ ] `W2-ROLLBACK-DEBIT-MODE-PARTIAL`: Rollback with `debit_mode=PARTIAL` drains balance up to available funds.

### 2.4 Rounds & grants
- [ ] `W2-CLOSEROUND-IDEMPOTENT`: Your wallet acknowledges `CloseRound`, and the call is idempotent on `op_id`.
- [ ] `W2-CLOSEROUND-WITH-NETTO`: `CloseRound` carries the round summary `net_win`, `bet_total`, `win_total`.
- [ ] `W2-G6-SETTLEGRANT-IS-ACKNOWLEDGED`: Your wallet acknowledges `SettleGrant` with OK, including zero total.
- [ ] `W2-G6-SETTLEGRANT-IDEMPOTENT`: `SettleGrant` replayed for one grant pays once.
- [ ] `W2-G6-SETTLEGRANT-CREDITS-TOTAL-WIN`: `SettleGrant` credits `total_win` (§5.9 of the Integration Guide): right after the `ok` reply the balance is up by exactly `total_win`. An unchanged balance fails: this call is the only place the free-round win reaches the player.

### 2.5 Transaction reconciliation
- [ ] `W2-RECONCILE-APPLIED`: `Reconcile` reports `APPLIED` for a completed `op_id`.
- [ ] `W2-RECONCILE-NOT_APPLIED`: `Reconcile` reports `NOT_APPLIED` for an unknown `op_id`.
- [ ] `W2-RECONCILE-UNKNOWN`: `Reconcile` reports valid `ReconcileState` enum.
- [ ] `W2-RECONCILE-CARRIES-OPERATOR-TX`: `Reconcile` for applied operation returns original `operator_tx_id`.

### 2.6 Non-financial lifecycle & notifications
- [ ] `W2-NOTIFY-EACH-KIND-ACK`: `Notify` acknowledges non-monetary lifecycle events.
- [ ] `W2-NOTIFY-FREEROUNDS-STARTED`: `Notify` `NOTIFY_KIND_FREE_ROUNDS_STARTED` event acknowledged.
- [ ] `W2-NOTIFY-FREESPIN-FINISHED`: `Notify` `NOTIFY_KIND_FREESPIN_FINISHED` event acknowledged.
- [ ] `W2-NOTIFY-SESSION-EXPIRED`: `Notify` `session_expired` event acknowledged.

### 2.7 Metadata, authentication & scope isolation
- [ ] `W2-PROVIDER-DATA-ECHOED`: `ProviderData` with raw payload in `CallMeta` accepted.
- [ ] `W2-AUTH-TOKEN`: `Authenticate` validates launch token and answers session profile.
- [ ] `W2-AUTH-INVALID-TOKEN`: Your wallet cleanly rejects `Authenticate` with an invalid launch token.
- [ ] `W2-TOKEN-EMPTY-IS-REJECTED`: Your wallet refuses a money call arriving with empty `launch_token`.
- [ ] `W2-TOKEN-BALANCE-WITHOUT-TOKEN`: `GetBalance` without `launch_token` answers from `player_ref` or refuses cleanly.
- [ ] `W2-G7-PLAYER-REF-IS-OPAQUE`: The player reference is carried through unparsed and unaltered.
- [ ] `W2-G8-BRAND-ISOLATION`: A session's money can't be moved from another brand.
- [ ] `W2-G5-GRANT-ISSUANCE-IDEMPOTENCY`: The aggregator, not the wallet, handles grant issuance idempotency.
- [ ] `W2-G10-DEMO-CANNOT-REACH-THE-WALLET`: A demo launch has no field that could ever address a wallet.

### 2.8 Error handling, retries & capabilities
- [ ] `W2-ERR-REFUSAL-IS-FAILED-PRECONDITION`: a business refusal answers with a typed error code on HTTP 200 (on gRPC: a status carrying `ErrorDetail`), never a bare `FAILED_PRECONDITION` and never an internal error.
- [ ] `W2-ERR-UNDECIDED-RETRY-SAME-OPID`: An undecided call retried with the SAME `op_id` moves money once.
- [ ] `W2-ERR-MALFORMED-IS-INVALID-REQUEST`: Your wallet refuses a malformed money request as `INVALID_REQUEST`, not 500.
- [ ] `W2-ERR-EACH-ERRORCODE-SHAPE`: Structured error responses conform to `ErrorCode` contract.
- [ ] `W2-RETRY-SAME-OPID-NEW-REQUESTID`: Your wallet recognizes a retry with SAME `op_id` and NEW `request_id` as an idempotent retry.
- [ ] `W2-CURRENCY-MISMATCH-REFUSED`: Your wallet cleanly rejects a request with currency mismatch against the player account.
- [ ] `W2-CAPS-DECLARED-EQUALS-BEHAVIOUR`: Declared capabilities in `wallet_capabilities` match runtime behavior.

### 2.9 Money-path delta (`W2-D1` … `W2-D6`)

The six checks of `../money-path/OPERATOR-API-MONEY-PATH-RULES.md` §3, required of every operator certifying on the v2 contract. The document numbers them `W2-DELTA-01` … `W2-DELTA-06`. `ga-operator-certify` prints them under the ids below.

- [ ] `W2-D1-DEBIT-AFTER-ROLLBACK-OF-UNKNOWN`: After a Rollback of an unknown original, your wallet refuses a Debit with that `op_id` with `ALREADY_ROLLED_BACK`. This holds at the original amount and at a different one. The balance never moves.
- [ ] `W2-D2-DUPLICATE-DEBIT-BALANCE-NOW-INSUFFICIENT`: A resent Debit whose stake no longer fits the balance returns the identical stored success. The check also runs with the session expired.
- [ ] `W2-D3-DUPLICATE-DEBIT-DIFFERENT-AMOUNT`: For the same `op_id` with a different amount, your wallet refuses with `IDEMPOTENCY_CONFLICT`. The stored result stays unchanged.
- [ ] `W2-D4-CREDIT-AFTER-SESSION-EXPIRY`: Your wallet accepts a Credit carrying the launch token of an expired session and credits it exactly once.
- [ ] `W2-D5-CONCURRENT-DUPLICATES`: Simultaneous identical Debits all get the same response. Your wallet applies exactly one debit.
- [ ] `W2-D6-EXPONENT-MISMATCH`: For a Debit with an exponent the player's currency doesn't use, your wallet refuses with `CURRENCY_MISMATCH`. No money moves, and the `op_id` stays unused.

---

## 3. Decision & sign-off

| Result | Status | Notes |
|---|---|---|
| **PASS** | [ ] | All 55 checks passed, allowing the structurally PARTIAL results the tool reports (`W2-G8-BRAND-ISOLATION` on the HTTP binding)—0 errors and 0 failures. |
| **FAIL** | [ ] | One or more tests failed with unexpected state or money loss. |
| **BLOCKED** | [ ] | Network connectivity or authentication issue prevented suite completion. |

**Certification Signatures:**

GA Integration Engineer: _________________________ &nbsp;&nbsp;&nbsp; Date: ______________
Operator Tech Lead: _____________________________ &nbsp;&nbsp;&nbsp; Date: ______________
