This is the exact problem that separates good distributed systems from chaotic
ones.
Because our dVFS has no central database, we cannot wrap multiple file writes
in a traditional SQL transaction (`BEGIN`, `COMMIT`, `ROLLBACK`). If moving an
item requires two network callsa `VFS_WRITE` to the new location and a
`VFS_DELETE` from the old onea network drop in between those two calls results
in an item being duplicated or destroyed.
To achieve atomicity without a database, we use a distributed systems pattern
called the **Escrow State Machine** (a lightweight variant of the Two-Phase
Commit, or 2PC).
Instead of moving items directly from Player A to Player B, we create a
temporary, isolated "Trade Window" in the VFS.
Here is how you execute a perfectly safe, atomic trade using only files and
folders.
### The Escrow Pattern: Step-by-Step
#### Phase 1: Initiation
Player A initiates a trade with Player B. The game engine creates a unique
directory for this specific transaction.
```text
```
#### Phase 2: Escrow (Moving to the holding zone)
Both players move the items they want to trade out of their inventories and
into the trade directory.
*Crucially: If a player crashes here, they haven't given the item to the other
player yet. The item is just sitting in a neutral folder.*
```text
# Player A escrows their sword
VFS_WRITE -> /trades/tx_9981/offer_A/item_sword.json
VFS_DELETE -> /players/hero/inventory/item_sword.json
# Player B escrows their gold
VFS_WRITE -> /trades/tx_9981/offer_B/item_gold.json
VFS_DELETE -> /players/wizard/inventory/item_gold.json
```
#### Phase 3: The "Ready" Lock
Both players click "Accept" in the UI. Instead of moving the items, they just
write their signature to the folder.
```text
VFS_WRITE -> /trades/tx_9981/ready_A.json -> { "timestamp": 12345 }
VFS_WRITE -> /trades/tx_9981/ready_B.json -> { "timestamp": 12347 }
```
#### Phase 4: The Atomic Commit (The Magic Step)
This is the single most important operation. The authoritative Node.js game
engine watches this directory. When it sees both `ready_A.json` and
`ready_B.json`, it performs **one single write**:
```text
VFS_WRITE -> /trades/tx_9981/status.json -> { "state": "COMMITTED" }
```
**This single file write is our transaction trigger.**
In a distributed system, you achieve atomicity by reducing the "point of no
return" to a single, indivisible operation. Writing `status: "COMMITTED"` is
that operation.
#### Phase 5: Settlement (Idempotent Cleanup)
Once the status is `COMMITTED`, the trade is legally complete. The engine now
physically moves the files to their new owners.
```text
# Give B's gold to A
VFS_WRITE -> /players/hero/inventory/item_gold.json
VFS_DELETE -> /trades/tx_9981/offer_B/item_gold.json
# Give A's sword to B
VFS_WRITE -> /players/wizard/inventory/item_sword.json
VFS_DELETE -> /trades/tx_9981/offer_A/item_sword.json
# Clean up the trade window
VFS_DELETE -> /trades/tx_9981/status.json
```
---
### Why this makes you immune to crashes
Imagine someone trips over the server's power cord at the worst possible
moment. Let's look at how the Escrow Pattern saves the data:
* **Crash during Phase 2 (Escrow):** Upon reboot, the engine sees a trade
stuck in `PENDING` for too long. It runs a "rollback" script, which simply
reads whatever is in `/trades/tx_9981/offer_A/` and writes it back to Player
A's inventory, then deletes the trade folder. Nothing is lost.
* **Crash during Phase 4 (Right before the Commit):** The status is still
`PENDING`. The engine treats it as a failed trade and rolls the items back to
their original owners.
* **Crash during Phase 5 (Settlement):** This is the dangerous one! The engine
moved the gold, but crashed before moving the sword.
* *The Fix:* Upon reboot, the engine sees `/trades/tx_9981/status.json` is
marked as `COMMITTED`. It knows this trade *must* happen. It resumes Phase 5.
Because our dVFS is idempotent, re-writing the gold to Player A's inventory
has no negative effect, and it seamlessly finishes moving the sword to Player
B.
By using directories as state machines, you have built a fault-tolerant
transaction manager out of nothing but text files and WebSockets.