When you add a custom route value (one other than "area", "controller", or "action"), you need to explicitly specify how to match it.
By default, you are expected to create a node for each potential route key value. For example, if you have a route key named "id" and you have records with the ids "1", "2", and "3", you would need to create a node for each id.
<mvcSiteMapNode title="Project 1" controller="Project" action="Details" id="1">
<mvcSiteMapNode title="Project 2" controller="Project" action="Details" id="2">
<mvcSiteMapNode title="Project 3" controller="Project" action="Details" id="3">
You have already discovered the alternative, which is to use preservedRouteParameters. This will make a node always match a route key regardless of its value, which is usually the ideal solution for administration pages that do CRUD operations.
<mvcSiteMapNode title="Edit Project" controller="Project" action="Edit" preservedRouteParameters="id">
Typically when you do that, you have to fix up the display a bit because it doesn't make much sense to have an edit node on the menu (you would typically pick edit out of a list of records) and when you select it you generally want the node to display the record you selected. You can do this using the FilteredSiteMapNodeVisibilityProvider and the SiteMapTitleAttribute.
For a complete downloadable demo of how you would typically set up a set of CRUD operations, see the blog post titled How to Make MvcSiteMapProvider Remember a User's Position.