It's tempting to think of a checkout session as a linear history where each snapshot is based on the previous one:
- package/1
- package/checkout/2/1
- package/checkout/2/2
- package/checkout/2/3
- package/2
- package/checkout/3/1
- package/checkout/3/2
- package/checkout/3/3
- package/3
Or to put it visually:

But that's not really the right way to think about it. They aren't strung together in a linear history. Each individual snapshot taken with vadvance is independent and equal in status. They are each based on the same version that the checkout session was started with:
- package/1
- package/checkout/2/1
- package/checkout/2/2
- package/checkout/2/3
package/2 (just a copy of package/checkout/2/3)
- package/checkout/3/1
- package/checkout/3/2
- package/checkout/3/3
package/3 (just a copy of package/checkout/3/3)
Or, to put it visually:

The right conceptual model is that a session is a collection of preliminary snapshots as you work on creating a change. When you perform a checkout (either exclusive or non-exclusive), you get a working copy based on some existing version. You accumulate changes over that version in your working copy. The basis version doesn't change as long as that checkout is active. Each snapshot is just an immutable copy of your working copy. It is based on the same original version and contains the set of changes you had accumulated at the point where you took the snapshot.
It's worth understanding this as it has important implications for hoe merging works. (See MergingFuture.) The current prototype merge scripts follow the actual history as it exists in Vesta. They do not artificially create a history that links snapshots within one session together into a linear history. This can affect the results of a merge.
Another way to think about it is that a session directory should represent the work of making a single change. Once you have completed an individual change, you should check it in. If you have multiple changes you need to make, or a complex change that may require several steps, you would probably be better served by using a branch. Branches can be checked out and checked back in just like packages (in fact they are packages) and thereby allow you to have a linear sub-history of changes.

See also the diagram on the vbranch man page.
Merging Example
Suppose you have a user that merges from successive versions of a non-exclusive checkout into a branch. It's tempting to think that the merge tool would see the history like this (solid black arrows mean "derived from", dashed red arrows mean "merged with"):

But actually, this is the history that the merge tool sees:

So when the user performs the second merge operation (merging pkg/checkout/40.user.1/20 into the exclusive checkout for creating the version "pkg/40.add_feature/2"), the merge algorithm will see two parallel sets of changes:
Those from pkg/40 to pkg/checkout/40.user.1/10
Those from pkg/40 to pkg/checkout/40.user.1/20
Because pkg/checkout/40.user.1/20 is not derived from pkg/checkout/40.user.1/10, the merge algorithm doesn't have any connection between those two sets of changes. It won't know to merge in just the changes leading from pkg/checkout/40.user.1/10 to pkg/checkout/40.user.1/20, because those two versions don't have a relationship indicating that one is derived from the other. This could result in merge conflicts between lines that are different from the original in both of those snapshots.