Skip to content

RevFramework – Sample Scene: 06_Currency_Idempotency

Goal

Teach retry-safe currency mutations using request identity:

Reason / SourceId / RID → real service mutation → same-RID replay → compare results and live balances.


What This Scene Demonstrates

This scene shows idempotency as observed service-stack behaviour.

The flow is:

Owner A → optional Owner B → ICurrencyService → operation with sourceId|rid:<token> → first call → same-RID replay → CurOpResult

  • Owner A is the primary wallet being mutated
  • Owner B is only required for Transfer A → B
  • RID is appended to SourceId as |rid:<token>
  • Run Once sends one real mutation request
  • Run Twice sends the same request twice with the same RID
  • The panel compares first-call and replay results
  • Live balances show whether the second call mutated again

Idempotency is service-stack behaviour, not a panel feature.

The service result is truth.


What To Look For

Use the CurrencyIdempotencyPanel to observe replay behaviour from the public API side.

  • Bindings

  • Owner A is required for all operations

  • Owner B is required only for Transfer
  • Service shows the resolved ICurrencyService stack

  • Reason / Source / RID

  • Reason explains why the mutation happened

  • Source identifies what triggered it
  • RID identifies this request instance
  • Effective SourceId shows the actual sourceId|rid:<token> value sent to the service
  • New RID creates a fresh request identity

  • Operation

  • Set writes an absolute balance

  • Credit adds funds
  • Debit removes funds
  • Transfer moves funds from Owner A to Owner B
  • These are real service calls, not fake replay simulations

  • Replay

  • Run Once sends one request with the current RID

  • Run Twice sends the same request twice with the same RID
  • Compare the first and second CurOpResult
  • Check live balances to see whether the second call changed state again

Sample Scope

This scene covers:

  • Building a RID-bearing SourceId
  • Running real Set / Credit / Debit / Transfer calls
  • Replaying the same operation with the same RID
  • Comparing first-call and replay results
  • Verifying observed behaviour through live balances
  • Demonstrating the public-API limitation of hostile consumer panels

This scene does NOT cover:

  • Inspecting internal decorators
  • Proving idempotency composition through reflection
  • Backend request stores
  • Persistent RID caches
  • Distributed transaction systems
  • Multiplayer replication or networking

Those are service composition or project-level concerns.


Authority Note

This scene may include a permissive sample authority setup so it runs without additional configuration.


Networking Reminder

RevFramework does not include networking.

For multiplayer projects, retry requests must be routed through your own networking and authority layer. Idempotency helps avoid duplicate effects, but server/host validation is still your responsibility.


How To Use

  1. Enter Play Mode.
  2. Toggle the CurrencyIdempotencyPanel with F8.
  3. Confirm the top bindings:

  4. Owner A is assigned

  5. ICurrencyService is resolved
  6. Owner B is assigned if testing Transfer
  7. Check Reason / Source / RID.
  8. Use New RID if you want a fresh request identity.
  9. Select a currency.
  10. Select an operation:

  11. Set

  12. Credit
  13. Debit
  14. Transfer
  15. Enter an amount.
  16. Press Run Once to send one request.
  17. Press Run Twice to send the same request twice with the same RID.
  18. Compare:

  19. first CurOpResult

  20. second CurOpResult
  21. live Owner A / Owner B balances

Failure Behaviour

Failures are shown through dependency messages, disabled replay state, or returned CurOpResult values.

Common causes:

  • Play Mode required

  • Idempotency is observed through live mutations and same-RID replay

  • Fix: enter Play Mode

  • Service missing

  • No ICurrencyService was resolved

  • Fix: add SceneCurrencyService, add CurrencyServiceBootstrap, or publish a composed service

  • Owner A missing

  • Owner A is required for all tests

  • Fix: assign Owner A or tag the player GameObject as Player

  • Owner B missing for Transfer

  • Transfer A → B needs a target wallet

  • Fix: assign Owner B or choose Set, Credit, or Debit

  • No RID token

  • Replay needs stable request identity

  • Fix: enter a RID token or press New RID

  • No currencies bound

  • No CurrencyDefinition assets are available

  • Fix: assign currencies in the Inspector or provide a CurrencySet

  • Invalid CurrencyId

  • The selected CurrencyDefinition has an invalid Id

  • Fix: correct the CurrencyDefinition asset

  • Invalid amount

  • Credit, Debit, and Transfer require an amount greater than zero

  • Fix: enter a positive amount

  • Second call mutates again

  • Same-RID replay did not suppress the duplicate effect

  • Fix: check that idempotency is composed into the service stack and that the RID-bearing SourceId is identical

  • Replay returns failure

  • The service rejected one or both calls

  • Fix: check the code/message, operation arguments, balance, authority, caps, escrow, and service composition

Behind The Scenes

The panel uses only public Currency APIs:

  • CurrencyResolve.ServiceFrom

  • resolves the active ICurrencyService

  • SourceId convention

  • appends |rid:<token> to the supplied source id

  • ICurrencyService

  • SetBalance

  • Credit
  • Debit
  • Transfer
  • GetBalance

  • CurOpResult

  • Success

  • Code
  • Message

The panel does not inspect decorators.

It cannot directly prove idempotency is present.

It observes first-call vs same-RID replay behaviour through public service results and live balances.


Key Takeaway

RID identifies a specific request instance.

Same RID means “this may be a retry.”

If idempotency is composed correctly, replay should not apply the mutation twice.