Lifecycle

Execution flow showing when each adapter and core function is called.

Initialization

1. DocumentStorage.load(key) → Load persisted CRDT bytes
↓
2. AutoCommit::load(bytes) → Initialize CRDT from bytes
↓
3. Database ready

Write: db.data.user.name = 'Alice'

1. PolicyEngine::authorize(actor, "write", "/user/name") → Check write permission
↓
2. doc.put(path, value) → CRDT mutation
↓
3. Observer::check_and_fire() → Notify observers if value changed
↓
4. DocumentStorage.save(key, doc.save()) → Persist snapshot (if auto-persist enabled)
↓
5. SyncAdapter.send(changes) → Push changes to coordinator (if connected)

Read: db.data.user.name.$value

1. PolicyEngine::authorize(actor, "read", "/user/name") → Check read permission
↓
2. doc.get(path) → Read from CRDT
↓
3. Return value

Manual Persist: db.persist()

1. doc.save() → Serialize CRDT to bytes
↓
2. DocumentStorage.save(key, bytes) → Write to storage

Peer Connects to Sync Coordinator

1. WebSocket.connect() → Peer opens connection
↓
2. PolicyEngine::authorize_subscription(patterns) → Validate subscription patterns
↓
3. doc.get_changes_since(peer_heads) → Compute delta since peer's last sync
↓
4. WebSocket.send(Sync { changes }) → Send changes to peer
↓
5. Peer: doc.apply_changes(changes) → Merge into local CRDT
↓
6. Peer: Observer::check_and_fire() → Fire observers for changed paths
↓
7. Peer: DocumentStorage.save() → Persist updated state (if auto-persist enabled)

Peer Pushes Changes to Coordinator

1. Peer: doc.get_changes() → Get all local changes
↓
2. Peer: WebSocket.send(Push { changes }) → Send to coordinator
↓
3. Coordinator: doc.apply_changes(changes) → Merge into coordinator's CRDT
↓
4. Coordinator: DocumentStorage.save() → Persist updated state
↓
5. Coordinator: Find matching subscribers by subscription patterns
↓
6. Coordinator: WebSocket.send(Broadcast { changes }) → Send to each subscriber
↓
7. Each peer: doc.apply_changes(changes) → Merge changes
↓
8. Each peer: Observer::check_and_fire() → Fire observers

Observer Registration: db.data.user.name.$observe(callback)

1. doc.get(path) → Read current value
↓
2. Store observer: { path, callback, last_value }
↓
3. Observer fires on future mutations/syncs to this path

Summary: All Adapter Methods

Adapter Method When
DocumentStorage load(key) Initialization
DocumentStorage save(key, bytes) Auto-persist or manual persist()
PolicyEngine authorize(actor, action, path) Every read/write
PolicyEngine authorize_subscription(patterns) Peer connects
Observer callback(new_value) After mutations, apply_changes
SyncAdapter send(message) Push changes to coordinator