🧪 RevFramework Currency — Testing Philosophy¶
This document explains how the Currency system is tested, what the tests are designed to protect, and what they intentionally do not claim.
This is not marketing material.
It is an engineering-facing overview of the testing philosophy behind the Currency system.
🎯 The Goal of the Tests¶
The Currency tests exist to protect:
- behavioural guarantees
- regression safety
- deterministic wallet behaviour
- explicit transaction semantics
- audit and idempotency correctness
- edge-case handling across composed service stacks
The tests are designed to answer questions like:
- “Does this behaviour still work after refactors?”
- “Did a supported public API contract accidentally change?”
- “Do failed mutations leave balances untouched?”
- “Do transaction rollback paths still behave consistently?”
- “Do composed wrappers still expose the right capabilities?”
- “Do audit, batch, escrow, authority, caps, and idempotency still interact correctly?”
The goal is predictability, not “perfect software.”
🔒 Hostile Consumer Tests¶
Most Currency tests are written as Hostile Consumer tests.
This means the tests interact with the system exactly the way a real Unity project would:
- through public APIs
- through supported interfaces
- through supported factories
- through supported service wrappers
- through supported adapters and seams
- without reflection
- without private-field access
- without editor-only shortcuts unless testing editor-authored assets
These tests intentionally avoid depending on implementation details.
If a Hostile test passes, the supported public Currency contract is behaving correctly.
✅ HappyPath Tests¶
Currency also has dedicated HappyPath tests.
These are not edge-case torture tests.
They prove that the system’s main intended workflows operate cleanly from a user-facing perspective.
HappyPath coverage focuses on flows such as:
- creating wallets
- crediting balances
- debiting balances
- transferring currency between owners
- spending cost bundles
- granting rewards
- restoring wallet snapshots
- composing common stacks
- resolving scene services
- using normal transaction flows successfully
These tests are deliberately readable.
Their purpose is to prove that the “normal developer path” works without needing to understand every internal decorator, policy, or failure branch.
⚙️ InternalTruth Tests¶
The Currency system also contains a smaller set of InternalTruth tests.
These tests validate internal framework assumptions that are important for long-term stability but are not part of the supported public API.
Examples include:
- decorator composition order
- internal RID parsing semantics
- policy preview assumptions
- transaction rollback boundaries
- escrow-first rollback behaviour
- hidden audit propagation through wrapper chains
- internal cache / pruning expectations
- capability exposure through composed services
InternalTruth tests are intentionally separated from Hostile tests.
They exist to protect framework integrity during future refactors.
They are not an invitation for users to rely on internals.
🧩 What the Currency Tests Validate¶
The current Currency test suite validates behaviour including:
Core Wallet Behaviour¶
- Wallet creation
- Balance reads
- Credit behaviour
- Debit behaviour
- SetBalance behaviour
- Transfer behaviour
- Invalid owner / currency / amount handling
- Event emission for successful mutations
- No event emission for failed mutations
Caps & Policies¶
- Minimum and maximum cap enforcement
- Clamp mode behaviour
- Fail mode behaviour
- SetBalance cap behaviour
- Transfer cap behaviour
- Policy sanitization
- Duplicate rule handling
- Transfer policy provider behaviour
Transactions¶
- Ordered staged operations
- Successful commit behaviour
- Failed commit behaviour
- Friendly-stack rollback
- Best-effort rollback boundaries
- Transfer transaction semantics
- Long-loop transaction stability
- Batch emission during transactions
Escrow & Hold Transactions¶
- Direct escrow hold / commit / release / expire behaviour
- TTL expiry behaviour
- No-TTL hold behaviour
- Destroyed-owner handling
- Read-only escrow inspection
- Owner token indexing
- HoldTxn success paths
- HoldTxn failure and release paths
- Repeated hold / release / expire cycles
- Require-escrow enforcement
Audit¶
- Audit metadata propagation
- Reason and sourceId preservation
- Newest-first ordering
- Per-owner audit isolation
- Capacity-bounded audit history
- Live audit subscriptions
- Unsubscribe behaviour
- No audit entries for failed mutations
- Hidden audit propagation in internal wrapper chains
Idempotency¶
- RID-based replay detection
- Replay scope by owner
- Replay scope by currency
- Replay scope by operation kind
- Replay behaviour for Credit / Debit / SetBalance / Transfer
- No mutation on replay
- No duplicate events on replay
- Capacity-bounded replay history
- Eviction behaviour
- Non-audit path passthrough
Authority¶
- Unauthorized mutation blocking
- Missing-authority behaviour
- Allow-all authority behaviour
- Denied Credit / Debit / SetBalance / Transfer
- No wallet mutation on denied operations
- No events or audit entries on denied operations
- Authority behaviour inside transactions and composed stacks
Batch Events¶
- Batch wrapper capability exposure
- One batch event per explicit emit
- Per-op events still firing during batches
- Cancel behaviour
- Empty batch behaviour
- Transaction batch behaviour
- HoldTxn batch behaviour
Persistence¶
- Wallet snapshot capture
- Restore success paths
- Restore invalid input handling
- Restore rollback on mid-failure
- Audit-aware restore metadata
- Large-scale capture / mutate / restore round trips
- Repeated restore cycles
- Surviving-owner restore behaviour after destroyed owners
Scene Resolution & Bootstrap¶
- Scene-local service resolution
- Active-scene fallback
- Inactive child service discovery
- Resolver cache invalidation
- Destroyed-service recovery
- Published override precedence
- Dispose-scope fallback behaviour
- Resolver churn stability
Definitions & Formatting¶
- CurrencyDefinition authored values
- CurrencySet lookup behaviour
- Currency ID normalization
- Missing / null definition handling
- Display formatting
- Grouped / plain / compact formatting
- Signed delta formatting
- Template replacement
Scale & Correctness¶
- Many-owner wallet isolation
- Bulk credit / debit correctness
- Many transfer correctness
- Global total preservation during transfers
- Failed operations at scale
- Repeated transaction loops
- Repeated escrow loops
- Repeated persistence round trips
🧠 Deterministic Test Infrastructure¶
The Currency tests use deterministic test infrastructure where needed, including:
- scene-created currency services
- manual time providers
- explicit authority fakes
- authored ScriptableObject policies
- controlled composed service stacks
- repeatable owner and wallet setup
- bounded-capacity audit and idempotency configurations
This allows difficult service-composition, lifecycle, and rollback paths to be tested reliably.
The goal is not to fake the framework into passing.
The goal is to put the real framework surfaces under controlled, repeatable pressure.
❌ What These Tests Do NOT Claim¶
The tests do not claim:
- the framework is bug-free
- every possible gameplay economy is covered
- multiplayer correctness is guaranteed
- third-party integrations are validated
- every project-specific adapter is safe
- all rollback paths are perfectly atomic in hostile external conditions
- all performance/stress limits are proven
The tests validate framework behaviour and guarantees — not every possible project implementation.
🧩 The Philosophy¶
RevFramework systems are designed around:
- explicit guarantees
- predictable behaviour
- transparent failure handling
- modular integration seams
- service-driven composition
- honest public API boundaries
The Currency tests exist to lock those guarantees down over time as the framework evolves.
The goal is not to hide complexity.
The goal is to make Currency behaviour understandable, stable, and intentional.
TL;DR¶
The Currency tests are designed to protect guarantees, not pretend software can never fail.
Hostile tests validate supported public behaviour.
HappyPath tests prove the normal developer workflow works.
InternalTruth tests protect hidden framework assumptions.
Together, they help keep Currency predictable as RevFramework evolves.