Regardless of whether state.Store returns an error or not,
it should never result in a corrupted state.
This commit adds checks to UpdateBranch
to ensure that the result of applying a change
does not leave the state in a corrupted state:
no cycles, and no references to untracked branches.
This also discovered a case when changing the trunk would leave us in a
corrupt state: branches would point to the old trunk, which was
untracked.
This is tested with a fuzz test and a property-based test using rapid.
Doing this right does require loading the entire branch graph.
In the future, it might be worth reducing the number of times
we do this per command -- perhaps by storing it in memory,
or by maintaining a reverse index of base->branches in the store too.
Regardless of whether state.Store returns an error or not, it should never result in a corrupted state.
This commit adds checks to UpdateBranch to ensure that the result of applying a change does not leave the state in a corrupted state: no cycles, and no references to untracked branches.
This also discovered a case when changing the trunk would leave us in a corrupt state: branches would point to the old trunk, which was untracked.
This is tested with a fuzz test and a property-based test using rapid.
Doing this right does require loading the entire branch graph. In the future, it might be worth reducing the number of times we do this per command -- perhaps by storing it in memory, or by maintaining a reverse index of base->branches in the store too.