Skip to content

feat(individuality): register for the game in one call - #479

Merged
Nemanya8 merged 9 commits into
mainfrom
nm-game-registration
Oct 19, 2026
Merged

Nemanya8 merged 9 commits into
mainfrom
nm-game-registration

Conversation

@Nemanya8

Copy link
Copy Markdown
Contributor

Adds game registration to @parity/product-sdk-individuality, so every product that signs players up for the weekly game (Jollity's app and chat, Humanity) shares one implementation instead of its own copy. Built on the package's existing lite-signup, bind and airdrop pieces.

  • registerForGame(chain, capabilities, options) runs seat → bind → draws → sign. It reads the chain before each step, so running it again resumes where it stopped. Draw entries never block the sign-up. It resolves at the best block by default, and an abort before the broadcast sends nothing.
  • Every outcome and GameRegistrationError carries a report and says which step failed and whether a retry can help (registrationRetryDelay gives the backoff).
  • readGameSeat / deriveSeat give the route: returning, free, deposit or unfunded. bindGameSeat runs the bind on its own.
  • GAME_PRODUCT_NAME, GAME_ACCOUNT_INDEX, gameProductId name the game account in one place.
  • New /host entry: hostGameRegistrationCapabilities({ tld }) builds the capabilities from a Polkadot host. The main entry imports neither host nor tx.

Ported from jollity-next (game-chain/src/engine.ts, protocol/src/seat.ts). Changeset in pending-changesets/ (individuality + @parity/product-sdk minor).

@Nemanya8
Nemanya8 marked this pull request as draft October 19, 2026 10:05
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

📦 Bundle size impact

Comparing 2026-10-19T16:24:05.832Z → 2026-10-19T16:24:04.315Z

Package Entry Bundled before Bundled after Δ Ship gzip Δ Shake ratio
🟡 @parity/product-sdk ./individuality 127.8 KB 142.2 KB +14.4 KB (+11.2%) 0 B —
🟢 @parity/product-sdk ./individuality/host — — new entry — —
🟢 @parity/product-sdk-individuality ./host — — new entry — —

Thresholds — 🟡 ≥10% or ≥5.0 KB · 🟠 ≥20% or ≥15.0 KB (bundled). Percentage only applies once the baseline is ≥ 10 KB. Informational — this check never blocks merge.

@Nemanya8
Nemanya8 marked this pull request as ready for review October 19, 2026 10:29
@Nemanya8
Nemanya8 requested a review from peetzweg October 19, 2026 10:30
@peetzweg

Copy link
Copy Markdown
Member

Nice work. Seat → bind → draws → sign reads the chain before every step, so a retry picks up where it stopped. It ports cleanly from jollity, and the in-source tests cover the decisions well. One blocker and a few smaller things.

Blocker: the game account index should default to 0, not be hard-coded to it

Moving to 0 is right: the reason we played on 1 is gone. The native DIM2 game was switched off on Android:

It was then removed from iOS:

So this one can be closed with it:

Two things before it merges:

  1. Make the index an option that defaults to GAME_ACCOUNT_INDEX (0), e.g. hostGameRegistrationCapabilities({ tld, accountIndex? }). With a hard-coded index, every future move needs an SDK release, a product still on an older SDK silently plays on another account, and there is no escape hatch for a spent index in test sessions.
  2. jollity and humanity-spa have to move to the same index together. Both play and read on index 1 today: jollity signs up and reads the player there, and humanity-spa reads the seat and registers the Score participant there. Game.LiteInvites pins a lite person's free seat to one account for good, so one product on 0 and the other on 1 fight over the alias. humanity already hit that once and turned its own bind off. A returning player's Score record also sits on the index-1 account, so on 0 they would come up as new. The switch has to land in both in the same release.

Smaller

  • MEMBERS_PALLET_INSTANCE = 67: please read the Members pallet index from metadata. Previewnet, nextv2 and production can drift apart, and a hard-coded 67 then fails as a quiet no-lite-key.
  • Draws can block the sign-up. On a stale binding, liteProof(capabilities.personhood!, await facts()) in the draws step sits outside the try. A failed personhood read throws out of the draws step and fails the whole registration, which contradicts "draw entries never block the sign-up".
  • The new /host entry can't be reached through @parity/product-sdk. The umbrella's ./individuality is export * from "@parity/product-sdk-individuality", which is the main entry only. The PR adds a second entry, @parity/product-sdk-individuality/host, and the umbrella has no path to it (its ./host is product-sdk-host, something else). Products that depend on the umbrella and not on the individuality package directly, such as humanity-spa, get registerForGame but not hostGameRegistrationCapabilities. They would have to add @parity/product-sdk-individuality as a second dependency and keep its version in step with the umbrella, or write the capabilities by hand. That is exactly the duplication this PR removes. The changeset bumps the umbrella as if it ships the feature. Suggest adding an ./individuality/host export to the umbrella (export * from "@parity/product-sdk-individuality/host"), next to ./individuality.
  • code is meant to be a chain error name, but it sometimes holds a free-text message. errorName digs out the innermost type of a dispatch or validity error, such as NoRegistration. When there is none (a dropped socket, a host refusal, a PAPI or JS error), it falls back to error.message. The result becomes GameRegistrationError.code, report.signUp.code and the bind refusal's code. Every product will put these straight into telemetry, as jollity does into Sentry, and probably into retry logic and UI copy too, so they need to be a small, stable set. As free text, every distinct message (with addresses, block hashes or host wording in it) becomes its own value: dashboards can't group them, a reworded upstream message silently breaks any code === "…" check, and NOT_RETRYABLE_SIGN_UP.has(code) can never match one. Suggest a closed union of codes: chain error names, plus a few of our own like Timeout, Aborted, HostRefused, Network and Unknown. The message and the original error would ride along separately (message / cause).

@Nemanya8

Copy link
Copy Markdown
Contributor Author

Thanks Philip, addressed in a2bd8b7 and b79b4b5.

  1. Index: hostGameRegistrationCapabilities({ tld, accountIndex? }), defaulting to GAME_ACCOUNT_INDEX (0).
  2. Moving both products together: agreed, but that belongs in the products, so it's out of this PR. Until then, accountIndex: 1 keeps a product where it is.
  • MEMBERS_PALLET_INSTANCE: removed. The 67 was only used to find the key in the listRingVrfKeys answer, where the ring comes back with or without a PalletInstance. The prover now matches on chain + CollectionId (an exact match wins, two different pallets match nothing) and proves under the ring as the key declares it. Android's ring locator and humanity's declaresRing already match this way, and the /host builder doesn't need a chain or metadata.
  • Draws blocking the sign-up: the re-point proof is now made when signing, so a failed personhood read never fails the draws.
  • Umbrella: added @parity/product-sdk/individuality/host.
  • Codes: always a name now, either the chain's error name or one of GameRegistrationOwnCode (Timeout, Network, HostRefused, Unknown, …). The error text goes in message / cause.

Comment thread product-sdk/packages/individuality/src/host.ts Outdated
Comment thread product-sdk/packages/individuality/src/register-game.ts Outdated
Comment thread product-sdk/packages/individuality/src/register-game-errors.ts
@Nemanya8
Nemanya8 enabled auto-merge (squash) October 19, 2026 16:03
@Nemanya8
Nemanya8 disabled auto-merge October 19, 2026 16:04
@Nemanya8
Nemanya8 merged commit 7983a87 into main Oct 19, 2026
14 checks passed
@Nemanya8
Nemanya8 deleted the nm-game-registration branch October 19, 2026 16:44
@TarikGul TarikGul mentioned this pull request Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants