the encrypt/decrypt hooks existed but the write path wrote values straight to
the column, so a sensitive setting would have gone in as plaintext. closed it:
- sensitive values serialize + encrypt before they persist (base64 aes-gcm over
the json), and updates now carry the is_encrypted flag through
- non-sensitive settings are untouched — still plain json, same as before
- audit log redacts sensitive old/new values instead of recording them raw
round-trip test proves sensitive values never hit the column in plaintext and
still decrypt back; non-sensitive stay readable. no backfill needed — nothing
writes secrets through this path yet, the defaults are empty.
builds clean, vet quiet, tests pass.