17 lines
1.1 KiB
Markdown
17 lines
1.1 KiB
Markdown
# Attempt is a separate aggregate holding a ledger
|
|
|
|
**Playthrough** and **Attempt** are separate aggregate roots rather than one root containing the other, and an
|
|
Attempt records a *ledger* — coins found, coins spent, skills bought — rather than just a purse of coins found.
|
|
Separate roots keeps each aggregate small and gives the Attempt its own lifecycle, since it is never persisted.
|
|
The ledger exists so that the rule "nothing survives an Attempt unless you complete the level" applies to
|
|
purchases too: under the previous model `RemoveCoins` drained session coins and then debited banked coins
|
|
immediately, so buying a skill mid-level and then dying lost both the coins and the skill.
|
|
|
|
## Consequences
|
|
|
|
- Affordability is a cross-aggregate **read** (`attempt.CoinsFound + playthrough.Bank >= cost`). Reads may cross
|
|
scopes; writes may not.
|
|
- Purchasing writes only the Attempt. The only operation touching both roots is Commit, which has exactly one
|
|
call site.
|
|
- Discarding an Attempt undoes purchases rather than refunding them — under the ledger they never happened.
|