When men tries to create a tree:
- create root -- keep the object
- add child 1 -- root became non-leaf
- add sub-child -- root has now out-dated rgt
- add child 2 -- will go wrong from this point
- add sub-child
This scenario occurs when men tries to insert a whole subtree at once.
The problem is in NS_Node.get_tree(), which uses outdated lft/rgt. The method is used by get_last_child() > get_children() > get_descendants(), which is used by add_child when root node is not leaf anymore (after first insert, we update rgt + 2). Because rgt is outdated we will not get the whole tree, so get_last_child() will return the wrong node.
Easy fix: explain this in the documentation and mention explicitly that every operation that modifies the tree must fetch a fresh parent node just before the operation (fetch parent, add child, throw reference to parent away).
Better fix: introduce builder object, used to create larger subtrees at once.
node.builder().add_child(**params)\
.add_child(**params).pop()\
.add_child(**params)\
.commit()
Every method returns a builder instance with only add_child(), add_sibling(), pop() (return parent builder) and commit() methods. The commit() will shift rgt's at once and create the complete list of objects. Builder covers only tree creation, updates/deletions are perfect as they are right now. The documentation should mention that whole (sub)trees must be created via builders only.
Even better fix: remove all individual add_*() methods from nodes, inserts should be performed through builders only. At commit use fresh lft/rgt/depth/tree_id. Again, move and delete are individual operations on nodes.
The worst possible fix: keep track of all instantiated objects and update lft/rgt's. Please, do not do this.
If you like the idea, I can implement this and send the patch.