fix DotDict .get() bug across curiosity_queue, mentionable, and blog tools
atproto SDK's DotDict intercepts attribute access via __getattr__,
which means .get() resolves to DotDict["get"] (None for a missing key)
instead of dict.get(). Calling None("key") then raises:
TypeError: 'NoneType' object is not callable
This broke the entire exploration loop — every exploration window since
Apr 8 (6 consecutive failures over 3 days) failed with this exact error
on claim() at r.value.get("status"). The curiosity queue had a pending
item (mycelnet.bsky.social) that was never explored.
Also fixes:
- mentionable.py: latent — the mentionConsent record doesn't exist on
phi's PDS yet, so the .get() call was caught by the except block.
Would have failed the same way once someone opts in to mentions.
- blog.py: list_blog_posts used isinstance(val, dict) guards which
silently fell through to defaults (DotDict is not a dict subclass),
so all blog posts showed as "untitled" in listings. The title-
duplicate check also silently failed, comparing "" == title.
Fix: use bracket access (val["key"]) for required fields on DotDict
values. For blog.py, wrap with dict(rec.value) at point of use so
.get() with defaults works naturally for optional fields.
Found by actually trying to reproduce the exploration failure locally
instead of theorizing about it.