- matrix: drop cryptohelper LoginAs so device.json creds aren't
invalidated on every restart by Init's re-login
- matrix: thread ctx through PostThreadedReply; bot dispatcher derives
per-command ctx from app lifecycle so SIGTERM cancels in-flight work
- matrix: isTokenValid verifies /whoami user_id matches configured one
- matrix: loadDevice distinguishes missing file from corrupt parse;
refuse to silently overwrite a corrupt device.json
- matrix: Start checks Syncer type assertion and returns error
- arr: parseLookup skips empty-title items and extracts existing id
- bot: skip Add when Result.Exists; reply "already in library"