decrypt_text_at_rest previously swallowed any hex-decode, AEAD-decrypt,
or UTF-8 failure with a fallback to an empty string, so a corrupted or
tampered body column read back as an empty body instead of surfacing
an error -- defeating the AEAD's integrity guarantee exactly where it
matters: detecting tampering on read. Change its signature to return
Result<String, CipherError> and propagate failures through every read
call site in db.rs as the new DatabaseError::Decryption variant.
Refs #237#162