After much investigation, I found that if I provided the ID defined in the model as part of the add() method and followed with a sync() method call, that the _pristineData property was not being updated properly.
See http://dojo.telerik.com/@aw232/OZuKA/2 for an example I created to illustrate what I mean. Clicking the “Click Me” button calls add(), including a value for the id as defined in the model ("ProductID"), followed by a sync() method call. The product appears to be successfully added to the grid, but clicking on edit and then cancel removes the row. This is because the _pristineData property is not updated after the sync(), so the DataSource reverts back to that data when the cancel event is called. Additionally, neither the Create nor Update Transports are being called.
However, if I don’t provide the ID, as defined in the model, the Create Transport function is called, and the _pristineData is being successfully updated when I called the sync() method. See http://dojo.telerik.com/@aw232/uKIji/2 for an example. The code here is identical to the first snippet, except that the model now uses “ID” as the id, which is not provided in the add() method. As you can see, the create transport function is successfully called and _pristineData is updated and thus, clicking cancel does not remove the row from the datasource.
I would expect that sync() would push the current data to _pristineData either directly, or by calling the Create or Update transports as necessary.