sorry, you're right, i did see later that SyndicatedPosts may have both null permalinks and syndicated urls. that's probably better than either a compound key or not storing posts w/o syndicated urls.

another alternative is to store SyndicatedPosts as children of their Source entity, so we can use ancestor queries and write them inside a transaction:
https://developers.google.com/appengine/docs/python/ndb/entities#Overview
https://developers.google.com/appengine/docs/python/ndb/queries#ancestor