# Changelog & migration guide: Operator API v2

## 2.0.0—2026-09-27

- **`launch_game` replay after the session ends (text correction, GA's behaviour is unchanged).** The guide (§4.1, Appendix A.2) said the same `token` always returns the same session. It does only while that session is open. Once the session is closed (`close_session`, or a newer launch of the same game for the same player) or past `expires_at`, the same `token` gets `409` `ERROR_CODE_IDEMPOTENCY_CONFLICT` (`session_token_conflict`): GA never reopens a closed session. While the first launch with a `token` is still running, a repeat gets `503` `ERROR_CODE_INTERNAL` with `retryable: true` (`launch_in_progress`). Don't retry the `409`; launch with a fresh `token`.

## 2.0.0—2026-09-25

- **One error model.** Every error from `/v2/aggregator/*` and `/v2/features/*` is one `application/json` body `{"code", "message", "retryable"}` (`ErrorDetail`, codes from the closed `ERROR_CODE_*` list), including signature and key problems (401 → `ERROR_CODE_INVALID_REQUEST`, 403 → `ERROR_CODE_BUSINESS_REJECTED`) and a read-only key on a write call (403). `message` starts with a stable token. GA doesn't change `/v1` answers.
- **New event `round.failed`** on the event stream (§4.6), payload `Round`. Two new `RoundStatus` values. `ROUND_STATUS_FAILED = 4`—your wallet declined an operation of the round, no money moved. `ROUND_STATUS_REFUND_FAILED = 5`—GA couldn't complete a rollback it owed, the stake stays debited, and the round needs manual reconciliation. A parser that ignores unknown enum values keeps working. Subscribe to `round.failed` to see these rounds.

### Operators already live on v2

**What doesn't change.**
- GA doesn't remove or rename any published method, field, enum value, route, header, or envelope.
- The only additions are the error code `IDEMPOTENCY_CONFLICT` and the response field `original_found`. The closed enum is 15 codes plus the `ERROR_CODE_UNSPECIFIED` default.

**What may change for you.** Check each item against your implementation.

1. **Unknown original.** If you return `UNKNOWN_ORIGINAL` to a Rollback or to a Reconcile, change to a success with `original_found=false` for Rollback, and to `NOT_APPLIED` for Reconcile. Certification check W2-G4 already requires success for a Rollback of an unknown original.
2. **Barrier.** If you don't remember the id of an unknown original, start remembering it. The Debit must check it in the same atomic step that records the debit.
3. **Order of checks.** If you check session, player status, limits, or balance before the `op_id` lookup, reorder per item 2.2.
4. **Late Credit, Rollback, and SettleGrant.** If you refuse them for session, player block, or limits, stop doing so (item 2.4).
5. **Same `op_id`, different fingerprint.** If you currently return the stored success or apply the new request, return `IDEMPOTENCY_CONFLICT` (item 2.3).
6. **Retention.** Keep `op_id` records for at least 4 months. For v1 bridges the 7-day window remains the hard minimum.
7. **Concurrent duplicates.** Serialise per `op_id` (item 2.6).
8. **Validation.** Apply the mappings of item 2.8.
9. **Promo and bonus credits.** Don't require a bet or a live session for them (item 2.10).
10. **New certification checks.** The six checks of section 3 apply to operators certifying on the v2 contract.

**Legacy behaviour GA tolerates.**
- Some operators answer "transaction not found" to a Rollback and don't guarantee the barrier of item 2.1.
- GA treats such an answer as final only if GA sent THAT Rollback after `original.ts + 300 s`. This relies on the operator rejecting the stuck original by its timestamp once the window has passed.
- GA resends an earlier Rollback after the window.
- The same holds for `Reconcile: NOT_APPLIED` of an unknown DEBIT on native v2 bindings, where GA calls Reconcile before Rollback. It's final only if GA sent that Reconcile after the window. Otherwise GA proceeds to Rollback.
- This applies to Debit/DebitCredit only. For a Credit, `NOT_APPLIED` means "resend it". GA never rolls back a Credit.
- Operators on the v2 contract certify the barrier, so for them "not found" is final at once.

---

## Version 2.0.0 (2026-09-13)

Operator API v2 is a major architectural evolution unifying Game Alligators' operator integration into a single canonical Protobuf core (`ga.operator.v2`). GA serves it over three transports: native gRPC, HTTP/JSON (protojson), and the Softgaming-compatible adapter.

---

### Key architectural enhancements

#### 1. Single canonical contract across three transports
- **v1**: gRPC v1 and HTTP v1 had separate definitions.
- **v2**: All three transports use the one Protobuf package in `proto/`.

#### 2. Deterministic idempotency: `op_id` vs `request_id`
- **v1**: A gRPC v1 `Rollback` carried a GA id instead of your original `op_id`, and a retry wasn't distinguished from a new operation.
- **v2**: `op_id` is the business operation deduplication key generated deterministically by GA for every distinct wager, win, rollback, or settlement. Replays with the identical `op_id` return the original cached response and never move balance twice. `request_id` is an ephemeral universally unique identifier (UUID) generated per network attempt / retry.

#### 3. Structured metadata & provider passthrough (`ProviderData`)
- **v1**: Provider attributes, jackpot flags, and raw payloads didn't reach the operator.
- **v2**: Every money request carries `CallMeta` with typed `ProviderData` containing the provider slug, round details, and raw provider payloads.

#### 4. Expanded financial primitives
- **Atomic `DebitCredit`**: Single remote procedure call (RPC) performing atomic wager and payout in one ledger step.
- **`CloseRound` with Netto**: Explicit round closure notification providing the round result (`net_win`, `bet_total`, `win_total`).
- **Flexible `Rollback`**:
  - Supports partial amount rollback **of a Credit**. A rollback of a Debit is always full.
  - Supports `debit_mode` controlling operator ledger behavior when reversing credits: `REJECT` (fail if insufficient balance), `ALLOW_NEGATIVE` (permit negative player balance), or `PARTIAL` (drain available balance).
- **`CreditKind` and `MoneyComponent`**: Clear distinction between regular wins, bonuses, promotional payouts, jackpots, and free spins, with optional balance component breakdowns.

#### 5. Explicit reconciliation & non-financial lifecycle
- **`Reconcile`**: Allows GA to query whether an uncertain or timed-out operation completed on the operator ledger, returning `APPLIED`, `NOT_APPLIED`, or `UNKNOWN`, along with the operator transaction ID.
- **`Notify`**: Asynchronous notification for non-monetary lifecycle events such as free spins start/end, session expiry, and responsible gaming limits.

#### 6. Dynamic capability negotiation (`wallet_capabilities`)
- Operators declare supported actions in their configuration or via `GetOperatorCapabilities`. GA doesn't send optional actions you haven't declared.

#### 7. Standardized error handling
- Structured `ErrorCode` enum mapping cleanly across gRPC status codes and HTTP envelopes, distinguishing between retryable transport errors (`MAINTENANCE`, `RATE_LIMITED`, `INTERNAL`) and terminal business refusals (`INSUFFICIENT_FUNDS`, `LIMIT_EXCEEDED`, `SESSION_EXPIRED`).

#### 8. Automated certification (`ga-operator-certify`)
- The suite provides 55 automated test cases (`W2-*`) validating idempotency, edge cases, error shapes, and brand isolation across all transports.

---

### Migration checklist: upgrading from v1 to v2

| Feature | v1 (Legacy) | v2 (Current) | Action Required |
|---|---|---|---|
| Contract source | v1 OpenAPI / `ga.operator.v1` | `proto/*.proto` in this package | Regenerate stubs from v2 proto or implement v2 HTTP/JSON routes. |
| Base URL / Prefix | `/v1/wallet/{action}` | `/v2/wallet/{action}` | Mount routes under `/v2/wallet/*`. |
| Rollback reference | GA id | `original_op_id` matching initial `op_id` | Match `original_op_id` directly against previous operation records. |
| Wager & Win in one call | Not supported or ad-hoc | `POST /v2/wallet/debit_credit` | Implement atomic net ledger balance adjustment if capability is enabled. |
| Round closure | Optional `end_round` | `POST /v2/wallet/close_round` | Accept the `net_win`, `bet_total`, `win_total` summary. |
| Reversals | Binary refund | `POST /v2/wallet/rollback` | Support partial amount and `debit_mode` flags. |
| Uncertain tx resolution | Manual database review | `POST /v2/wallet/reconcile` | Implement query lookup by `op_id`. |
| Conformance testing | Manual checklist | `ga-operator-certify` with 55 checks | Run the certification command-line tool against your staging endpoint. |
