u/jbosch/DM-1188

May be easiest to review commit-by-commit, as the content is well separated and the logs should describe the purpose of the change.  The biggest by far is 8c99a21988cf95908d61bab775722d7fc100c699, which involves two new files that replace (and unify, and expand) the code in 13feffe1b704733fdb667b7e4d8f7b5b9e763861 and 6d5f02e10a1f562c5bb18874efcb8014c1d5b4f0.  I've tried to include very complete API documentation and some detailed implementation notes, which I hope will help with the review.