Read-only ActivityPub → atproto bridge for the threadiverse using Coves lexicons

fix(ap): parse Mbin objects whose source is a bare URL string master

Mbin sends a link post's external URL in `source` as a plain string; Lemmy and the AS2 spec use a {content, mediaType} object. ap.Source only accepted the object, so ParseObject rejected the whole object and every Mbin link post in a bridged community was dropped, on backfill and on live inbox delivery (seen on the startrek.website backfill, 2026-08-22). Object.UnmarshalJSON now decodes `source` only when it is a JSON object. Any other shape (string, number, array, bool, null) leaves Source nil, and the body comes from the rendered HTML `content`. A malformed object still fails, with an error naming the object id and `source`. Mbin's link URL is still bridged as the external link via its `attachment` Link entry. Changes: - vocab.go: shadow `source` as RawMessage; decode objects only - add a hand-built fedia.io link-page fixture and parse tests for every source shape, including the Announce-wrapped form - add a backfill test that materializes the Mbin link page - MarshalJSON still emits only the object form Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>