Projection Record Row Mapper
object ProjectionRecordRowMapper
Translate the lineage records to and from the property maps the durable graph stores read and write. Kept separate from the stores (and free of any Drivine types) so the fiddly bits — typed reasons flattened to a key, enums stored by name, timestamps as ISO strings — can be unit-tested without a database.
Timestamps are written as ISO-8601 strings and parsed back, which keeps reads off the database's native temporal types and gives a single, predictable round-trip. A bad timestamp on read falls back to Instant.EPOCH rather than "now", so a corrupt record never looks freshly written.