Thomas,
== Proposed Solution == When adding/changing/removing a property or node, the logical operation should be recorded on a high level ("this node was added", "this node was moved from here to there", "this property was added"), first in memory, but when there are changes, it needs to be persisted (possibly only temporarily). When committing a transaction (usually Session.save()), the micro-kernel tries to apply the changes. If there was a conflict, the micro-kernel rejects the changes (it doesn't try to merge). The higher level then has to deal with that. One way to deal with conflict resolution is: 1) Reload the current persistent state (undo all changes, load the new data). 2) Replay the logical operations from the (in-memory or persisted) journal. 3) If that fails again, depending on a timeout, go to 1) or fail.
I like this approach. In general I think merging is very difficult if not impossible at all to get right and will always be based on some assumptions (intended semantics). I think we should not put this burden onto the micro-kernel but rather leave it to higher levels (or even end users) to do the/some merging.
Regarding 3) I'd include detailed error information on failure: which operations are part of the conflict and what constitutes the conflict. This makes it easier for the consuming API (end user) to resolve conflicts.
== API == Instead of the current API that requires the change log to be in memory, I suggest to use iterators:
Maybe better iterables? More flexible if multiple playbacks are needed. Michael